虽然使用了HTTPS协议进行通信,但我们的网络仍然可以被嗅探监听。
我们可以采取SSL Pinning的方式来避免这种事情发生。
使用AFNetworking和SSL绑定实现安全连接。
SSL Pinning
SSL Pinning,即SSL证书绑定。通过SSL证书绑定来验证服务器身份,防止应用被抓包。
取到证书
客户端需要证书(Certification file), .cer
格式的文件。可以跟服务器端索取。
如果他们给个.pem
文件,要使用命令行转换:
openssl x509 -inform PEM -in name.pem -outform DER -out name.cer
如果给了个.crt
文件,请这样转换:
openssl x509 -in name.crt -out name.cer -outform der
如果啥都不给你,你只能自己动手了:
openssl s_client -connect www.website.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > myWebsite.cer
好,我们拿到证书了。
把证书加进项目中
把生成的.cer
证书文件直接拖到你项目的相关文件夹中,记得勾选Copy items if neede
和Add to targets
。
AFSecurityPolicy
SSLPinningMode
AFSecurityPolicy是AFNetworking中网络通信安全策略模块。它提供三种SSL Pinning Mode
/**
## SSL Pinning Modes
The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes.
enum {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
}
`AFSSLPinningModeNone`
Do not used pinned certificates to validate servers.
`AFSSLPinningModePublicKey`
Validate host certificates against public keys of pinned certificates.
`AFSSLPinningModeCertificate`
Validate host certificates against pinned certificates.
*/
AFSSLPinningModeNone
:完全信任服务器证书;
AFSSLPinningModePublicKey
:只比对服务器证书和本地证书的Public Key是否一致,如果一致则信任服务器证书;
AFSSLPinningModeCertificate
:比对服务器证书和本地证书的所有内容,完全一致则信任服务器证书;
选择那种模式呢?
AFSSLPinningModeCertificate
:最安全的比对模式。但是也比较麻烦,因为证书是打包在APP中,如果服务器证书改变或者到期,旧版本无法使用了,我们就需要用户更新APP来使用最新的证书。
AFSSLPinningModePublicKey
:只比对证书的Public Key,只要Public Key没有改变,证书的其他变动都不会影响使用。
如果你不能保证你的用户总是使用你的APP的最新版本,所以我们使用AFSSLPinningModePublicKey
。
allowInvalidCertificates
/**
Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`.
*/
@property (nonatomic, assign) BOOL allowInvalidCertificates;
是否信任非法证书,默认是NO。
validatesDomainName
/**
Whether or not to validate the domain name in the certificate's CN field. Defaults to `YES`.
*/
@property (nonatomic, assign) BOOL validatesDomainName;
是否校验证书中DomainName字段,它可能是IP,域名如*.google.com
,默认为YES,严格保证安全性。
使用AFSecurityPolicy设置SLL Pinning
+ (AFHTTPSessionManager *)manager
{
static AFHTTPSessionManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:[AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]]];
manager.securityPolicy = securityPolicy;
});
return manager;
}
OK,现在我们使用manger
的请求都是安全连接了。