Swift 5 下如何为Starscream 4.0.4的WebSocket配置SSL证书实现安全通信
问题解答
1 无自定义证书配置也能正常连接的原因
你当前使用的FoundationSecurity(allowSelfSigned: true)配置会直接信任所有自签名证书,不会校验服务端返回的证书是否为你自行生成的对应证书,因此无需导入自定义证书即可完成连接。
你当前的服务端仅配置了单向SSL认证,仅要求客户端信任服务端证书即可建立连接,因此任何开启了自签名证书信任的客户端都能接入服务,这就是你担心的安全隐患的来源。
2 Starscream 4.x版本配置服务端证书钉住的方法
4.x版本废弃了旧的security属性,统一通过CertPinner相关类完成证书配置,操作步骤如下:
- 首先将你生成的pem格式证书转换为Xcode可识别的cer格式,执行以下命令:
openssl x509 -outform der -in cert.pem -out cert.cer - 将生成的cert.cer文件导入Xcode项目,确保勾选了对应应用的Target成员资格
- 初始化WebSocket时传入自定义证书完成钉住配置,代码示例如下:
var request = URLRequest(url: URL(string: "wss://mydomain.com:1234")!) request.timeoutInterval = 10 // 加载项目内的自定义证书 guard let certPath = Bundle.main.path(forResource: "cert", ofType: "cer"), let certData = try? Data(contentsOf: URL(fileURLWithPath: certPath)) else { fatalError("证书加载失败") } // 初始化pinner时指定仅信任传入的自定义自签名证书 let pinner = FoundationSecurity(certs: [certData], allowSelfSigned: true) socket = WebSocket(request: request, certPinner: pinner) socket?.delegate = self socket?.connect()
完成该配置后,客户端只会和持有对应证书的服务端建立连接,可有效避免中间人攻击。
3 实现仅你的应用可连接服务的方案
要实现只有携带对应证书的应用可访问服务,需要配置双向TLS认证,即服务端也会校验客户端的证书有效性,无有效证书的连接会被直接拒绝,配置步骤如下:
3.1 后端服务配置
修改node.js的https服务初始化参数,开启客户端证书校验:
const httpsServer = https.createServer( { key: fs.readFileSync('./certs/key.pem'), cert: fs.readFileSync('./certs/cert.pem'), // 开启客户端证书校验 requestCert: true, // 配置信任的CA证书,此处为你自行生成的自签名证书 ca: [fs.readFileSync('./certs/cert.pem')], // 直接拒绝无有效证书的请求 rejectUnauthorized: true }); httpsServer.listen(1234, function() { logger.log.info(filename + "Server is listening on port " + 1234); }); var wsServer = new webSocketServer({ httpServer: httpsServer, autoAcceptConnections: false });
3.2 客户端配置
首先将你的证书和密钥打包为PKCS12格式的客户端证书,执行以下命令,导出时按提示设置密码:openssl pkcs12 -export -out client.p12 -inkey key.pem -in cert.pem
将生成的client.p12导入Xcode项目,修改Swift端初始化代码,传入客户端证书:
var request = URLRequest(url: URL(string: "wss://mydomain.com:1234")!) request.timeoutInterval = 10 // 加载服务端证书用于钉住校验 guard let certPath = Bundle.main.path(forResource: "cert", ofType: "cer"), let certData = try? Data(contentsOf: URL(fileURLWithPath: certPath)), // 加载客户端证书用于服务端校验 let p12Path = Bundle.main.path(forResource: "client", ofType: "p12"), let p12Data = try? Data(contentsOf: URL(fileURLWithPath: p12Path)) else { fatalError("证书加载失败") } let p12 = FoundationSecurity.PKCS12(data: p12Data, password: "你导出p12时设置的密码") let pinner = FoundationSecurity( certs: [certData], allowSelfSigned: true, pkcs12: p12 ) socket = WebSocket(request: request, certPinner: pinner) socket?.delegate = self socket?.connect()
完成以上配置后,只有携带对应客户端证书的应用才能成功和服务端建立连接。
内容的提问来源于stack exchange,提问作者Sean Mayes
相关产品推荐
相关产品推荐

