# 生成自签名证书示例
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
# 启用TLS 1.2/1.3,禁用不安全的协议
ssl_protocols TLSv1.2 TLSv1.3;
# 配置安全的加密套件
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
# 启用HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
# 其他配置...
location / {
# 你的应用配置
}
}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
在Info.plist中添加ATS配置:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<true/>
</dict>
</dict>
</dict>
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// 1. 设置策略
let policies = NSMutableArray()
policies.add(SecPolicyCreateSSL(true, challenge.protectionSpace.host as CFString))
SecTrustSetPolicies(serverTrust, policies)
// 2. 验证服务器证书
var error: CFError?
if SecTrustEvaluateWithError(serverTrust, &error) {
// 验证成功
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
// 验证失败
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
// 预先计算证书的公钥哈希
let pinnedKeys = ["sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="]
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// 验证证书链
var secResult = SecTrustResultType.invalid
let status = SecTrustEvaluate(serverTrust, &secResult)
if status == errSecSuccess,
(secResult == .proceed || secResult == .unspecified),
let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
// 获取服务器证书的公钥
if let serverPublicKey = SecCertificateCopyKey(serverCertificate),
let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey, nil) as Data? {
let keyHash = serverPublicKeyData.sha256().base64EncodedString()
if pinnedKeys.contains("sha256/\(keyHash)") {
// 公钥匹配
completionHandler(.useCredential, URLCredential(trust: serverTrust))
return
}
}
}
// 验证失败
completionHandler(.cancelAuthenticationChallenge, nil)
}
服务器测试工具:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
iOS端测试:
证书不受信任错误:
TLS版本不匹配:
ATS阻止连接:
证书过期问题:
通过以上配置,你可以建立Nginx服务器与iOS应用之间安全的HTTPS通信通道,保护数据传输的安全性。