一:HTTPS
HTTPS就是将HTTP协议数据包放到SSL/TSL层加密后,在TCP/IP层组成IP数据报去传输,以此保证传输数据的安全;而对于接收端,在SSL/TSL将接收的数据包解密之后,将数据传给HTTP协议层,就是普通的HTTP数据。HTTP和SSL/TSL都处于OSI模型的应用层。
二:App Transport Security
WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通讯安全的一个重要方式。在 iOS 9 和 OS X 10.11 中,默认情况下非 HTTPS 的网络访问是被禁止的。当然,因为这样的推进影响面非常广,作为缓冲,我们可以在 Info.plist 中添加 NSAppTransportSecurity 字典并且将 NSAllowsArbitraryLoads 设置为 YES 来禁用 ATS。
不过,WWDC 16 中,Apple 表示将继续在 iOS 10 和 macOS 10.12 里收紧对普通 HTTP 的访问限制。从 2017 年 1 月 1 日起,所有的新提交 app 默认是不允许使用 NSAllowsArbitraryLoads 来绕过 ATS 限制的,也就是说,我们最好保证 app 的所有网络请求都是 HTTPS 加密的,否则可能会在应用审核时遇到麻烦。虽然昨天Apple通知ATS的限制推迟,但这事迟早都得做。
(苹果对ATS要求:)
Requirements for Connecting Using ATS
With App Transport Security (ATS) fully enabled, the system requires that your app’s HTTP connections use HTTPS and that they satisfy the following security requirements:
• The X.509 digital server certificate must meet at least one of the following trust requirements:
• Issued by a certificate authority (CA) whose root certificate is incorporated into the operating system
• Issued by a trusted root CA and installed by the user or a system administrator
• The negotiated Transport Layer Security (TLS) version must be TLS 1.2. Attempts to connect without TLS/SSL protection, or with an older version of TLS/SSL, are denied by default.
• The connection must use either the AES-128 or AES-256 symmetric cipher. The negotiated TLS connection cipher suite must support perfect forward secrecy (PFS) through Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) key exchange, and must be one of the following:
• TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
• TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
• TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
• TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
• TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
• TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
• TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
• TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
• TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
• TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
• TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
• The leaf server certificate must be signed with one of the following types of keys:
• Rivest-Shamir-Adleman (RSA) key with a length of at least 2048 bits
• Elliptic-Curve Cryptography (ECC) key with a size of at least 256 bits
In addition, the leaf server certificate hashing algorithm must be Secure Hash Algorithm 2 (SHA-2) with a digest length, sometimes called a “fingerprint,” of at least 256 (that is, SHA-256 or greater).
The requirements listed in this section are current as of this document’s publication date, with stricter requirements possible in the future. Changes to these requirements will not break app binary compatibility.
三:服务器自签名证书生成与配置
1.openssl生成证书
第一步,为服务器端和客户端准备公钥、私钥
//生成服务器端私钥
openssl genrsa -out server.key 2048
// 生成服务器端公钥
openssl rsa -in server.key -pubout -out server.pem
第二步,生成 CA 证书
//生成 CA 私钥
openssl genrsa -out ca.key 2048
// X.509 Certificate Signing Request (CSR) Management.
openssl req -new -key ca.key -out ca.csr
// X.509 Certificate Data Management.
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
第三步,生成服务器端证书
//服务器端需要向 CA 机构申请签名证书,在申请签名证书之前依然是创建自己的 CSR 文件
openssl req -new -key server.key -out server.csr
//向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.cr
第四步,生成cer文件
使用openssl 进行转换
openssl x509 -in server.crt -out server.cer -outform der
2.Nginx htts与证书配置
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.org;
ssl_certificate /etc/ssl/server.crt ;
ssl_certificate_key /etc/ssl/private/server.key;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
ssl_prefer_server_ciphers on;
}
3.Tomcat https与证书配置
使用OpenSSL生成的数字证书和私钥,如需要在Java或Tomcat环境下使用,需要先装其转换成PKCS#12编码格式的密钥库,才能使用keytool工具进行相应的管理。转换命令如下:
openssl pkcs12 -export -clcerts -inkey private/client-key.pem -in certs/client.cer -out client.p12
openssl pkcs12 -export -clcerts -inkey private/server-key.pem -in certs/server.cer -out server.p12
打开tomcat的配置文件 vim conf/server.xml
<Connector port="8443" protocol="HTTP/1.1"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/usr/local/ssl/server.p12"
keystoreType="pkcs12"
keystorePass="12345678"
四:App使用HTTPS步骤
1.检测站点https://m-dev.ws.cn/是否符合ATS要求
-使用命令
nscurl --ats-diagnostics --verbose https://m-dev.ws.cn/
-或者用腾讯云检测https://www.qcloud.com/product/ssl
(目前有一项还不符合,但亲测不影响使用,估计跟自建证书有关)
2.将服务器端给的crt证书转成cer
openssl x509 -in server.crt -out server.cer -outform der
3.修改AFNetWorking请求http的方法,加证书验证
+ (AFSecurityPolicy*)customSecurityPolicy
{
// /先导入证书
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"m" ofType:@"cer"];//证书的路径
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
// AFSSLPinningModeCertificate 使用证书验证模式
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
// allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
// 如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = YES;
//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = NO;
securityPolicy.pinnedCertificates = @[certData];
return securityPolicy;
}
4.info.plist中将NSAllowsArbitraryLoads的配置去掉,即不绕过苹果的ats限制
但需要对webview和又拍云相关请求设置例外(这个苹果审核可能还存在风险,如果有问题,到时候再修改)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>v0.api.upyun.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>voice.b0.upaiyun.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>mage.b0.upaiyun.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>http://voice-group.b0.upaiyun.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>http://image-group.b0.upaiyun.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>