/HTTPS

Primary LanguageObjective-C

##AFNetworking Nginx HTTPS自签名服务器安全通信

A.对于后台服务器所配置动证书如果是经过CA机构认证颁发的,那么用户用AFNetworking来访问后台接口完全无感觉,就和http一样的方式。

B.但是一个HTTPS的证书如果是知名CA机构认证颁发的,那么就会有问题,AFNetworking默认拒绝和这样的后台服务器通信,因为验证通不过,就和大家网页打开12306网站抢票一样,那个证书也不是经过CA颁发的,而是铁道部自己签名的一个证书。所以,对于中小型初创或是成长型公司来说,买一个https的证书也是需要花费不少费用的。

AFSecurityPolicy分三种验证模式:

AFSSLPinningModeNone

这个模式表示不做SSL pinning,只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书,这里是不会通过的。

AFSSLPinningModeCertificate

这个模式表示用证书绑定方式验证证书,需要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。

这里还没弄明白第一步的验证是怎么进行的,代码上跟去系统信任机构列表里验证一样调用了SecTrustEvaluate,只是这里的列表换成了客户端保存的那些证书列表。若要验证这个,是否应该把服务端证书的颁发机构根证书也放到客户端里?

AFSSLPinningModePublicKey

这个模式同样是用证书绑定方式验证,客户端要有服务端的证书拷贝,只是验证时只验证证书里的公钥,不验证证书的有效期等信息。只要公钥是正确的,就能保证通信不会被窃听,因为中间人没有私钥,无法解开通过公钥加密的数据。

1.生成服务器的KEY和证书签名

openssl genrsa -des3 -out server.key 1024 openssl req -new -key server.key -out server.csr openssl rsa -in server.key -out server_nopwd.key openssl x509 -req -days 365 -in server.csr -signkey server_nopwd.key -out server.crt

2.证书格式转换 由于iOS端Apple的API需要der格式证书,故用如下命令转换

openssl x509 -outform der -in server.crt -out client.der

3.nginx配置

server {
    listen 80;#HTTP默认端口80
    server_name tv.diveinedu.com;#主机名,与HTTP请求头域的HOST匹配
    access_log  /var/log/nginx/tv.diveinedu.com.log;#访问日志路径
    return 301 https://$server_name$request_uri;#强制把所有http访问跳转到https
}

server {
    listen 443;#HTTPS默认端口443
    ssl on;#打开SSL安全Socket
    ssl_certificate      /usr/local/etc/nginx/server.crt;#证书文件路径
    ssl_certificate_key  /usr/local/etc/nginx/server_nopwd.key;#私钥文件路径

    #server_name xxx.com;#主机名,与HTTP请求头域的HOST匹配
    access_log  logs/host.access.log;#访问日志路径
    location / {
        root /var/www/;#网站文档根目录
        index index.php index.html;#默认首页
    }
}
```OC

4.示例代码

NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"der"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *certSet = [NSSet setWithObject:certData];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:certSet];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
_manager.securityPolicy = securityPolicy;

AFHTTPResponseSerializer *serializer = [[AFHTTPResponseSerializer alloc] init];
serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
_manager.responseSerializer = serializer;

[_manager GET:@"https://192.168.47.112/" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
    
} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"%@", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"%@",[error localizedDescription]);
}];