我想阻止我的应用程序/服务器通信从MITM攻击,所以我试图设置SSL固定,但我在使用自签名证书使用AFNetworking 2.2时遇到问题.我认为这主要是我如何生成证书的问题.
我首先尝试根据这些说明生成自签名证书:
生成私钥:
sudo openssl genrsa -des3 -out server.key 2048
生成签名请求,并在询问公共名称时使用域名:
sudo openssl req -new -key server.key -out server.csr
生成证书:
sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
最后,将其转换为der
格式(因为AFNetworking 需要它)
sudo openssl x509 -outform der -in server.crt -out server.der
服务器是Ubuntu 12.04,运行ngninx + passenger来提供Rails 4应用程序.这是我的nginx服务器配置打开SSL的位:
server { listen 80; listen 443; server_name myapp.com; passenger_enabled on; root /var/www/myapp/current/public; rails_env production; ssl on; ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; }
重新启动nginx后,下载der
文件,将其添加到我的项目,并将其重命名为"server.cer"(因为AFNetworking要求证书使用.cer扩展名),我使用此代码打开我的AFHTTPSessionManager
子类的SSL固定:
client.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
然后,在第一次向服务器发出请求时,AFNetworking会尝试验证"信任在AFServerTrustIsValid
函数中是否有效:
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) { SecTrustResultType result = 0; OSStatus status = SecTrustEvaluate(serverTrust, &result); NSCAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); }
如果我在返回时放置一个断点,我可以看到结果总是如此kSecTrustResultRecoverableTrustFailure
.
如果我AFServerTrustIsValid
通过设置allowInvalidCertificates
为YES
安全策略来跳过该功能,则请求成功.但如果我不需要,我真的不想允许无效的证书.
回到绘图板,这个SO问题引导我参考本教程,创建一个自签名证书,同时创建一个CA. 我设置我的openssl.cnf文件是这样的:
[ req ] default_md = sha1 distinguished_name = req_distinguished_name [ req_distinguished_name ] countryName = United Kingdon countryName_default = UK countryName_min = 2 countryName_max = 2 localityName = Locality localityName_default = London organizationName = Organization organizationName_default = Eric Organization commonName = Common Name commonName_max = 64 [ certauth ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always basicConstraints = CA:true crlDistributionPoints = @crl [ server ] basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth nsCertType = server subjectAltName = DNS:myapp.com crlDistributionPoints = @crl [ crl ] URI=http://testca.local/ca.crl
然后使用这些命令生成所有内容.首先是CA的东西:
sudo openssl req -config ./openssl.cnf -newkey rsa:2048 -nodes -keyform PEM -keyout ca.key -x509 -days 3650 -extensions certauth -outform PEM -out ca.cer
然后是服务器的私钥:
sudo openssl genrsa -out server.key 2048
签名请求:
sudo openssl req -config ./openssl.cnf -new -key server.key -out server.req
证书:
sudo openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 100 -extfile openssl.cnf -extensions server -days 365 -outform PEM -out server.cer
最后der
文件:
sudo openssl x509 -outform der -in server.cer -out stopcastapp.com.der
当我更新并重新启动nginx时,下载并添加server.der
到我的项目(确保将其重命名为server.cer
和重置模拟器),我得到了相同的确切结果.
可怕的kSecTrustResultRecoverableTrustFailure
再次出现了丑陋的头脑.
我究竟做错了什么?我是否喜欢这一切是如何工作的,或者我是否需要调整一个小东西才能使它全部工作?如果你能以任何方式提供帮助,我真的非常感激(我已经解决了这个问题两天了).谢谢!