刘浩的技术博客

就当是做个笔记,顺便分享一些知识,更希望业界的交流

使用AFNetworking 3.x做https安全连接

使用AFNetworking 3.x做https安全连接,单向验证

制作自签名证书

对于一般的需求自签名证书足够了,这里可以自己制作一个CA证书,然后用CA给所有你要用到的证书签名,这样你就可以在所有安装了CA证书的iOS设备里面用此CA签名的证书。自己制作CA证书稍后再说(12306就是用的自己的CA颁发的自签名证书),先讲制作自签名证书。

如何使用OpenSSL去创建一个自签名的SSL证书

运行以下下命令去创建,你会跳过问题提示,CN就是你的服务器地址。 openssl req -x509 -sha256 -newkey rsa:2048 -keyout certificate.key -out certificate.crt -days 1024 -nodes -subj '/CN=localhost'req 这个命令会生成两个文件在当前目录,一个私钥文件和一个crt证书文件,你能看到一个.key后缀名的私钥文件,它是没有密码与之关联的,如果你想使用密码,去掉-nodes选项就可以了。

转换成AFNetworking可识别的cer格式文件

运行以下命令可以转换格式,然后改成后缀名cer,AFNetworking可识别的。 openssl x509 -in server.crt -outform der -out "server.der"

生成pfx文件

转成c#能使用的证书,用c#写web api做后台其实格式和java使用的.p12是一样的只是后缀名不同。(此文件包含了私钥和证书),我这里设置了密码"123" openssl pkcs12 -export -out certificate.pfx -inkey certificate.key -in certificate.crt

制作CA证书

其实就是制作一个证书作为CA证书,步骤和制作自签名证书一样,名字不同而已。 openssl req -x509 -sha256 -newkey rsa:2048 -keyout CA.key -out CA.crt -days 1024 -nodes -subj '/CN=localhost'req

使用CA签发证书

生成csr文件,和一个私有key openssl req -newkey rsa:2048 -keyout server.key -out server.csr -nodes -subj '/CN=localhost'

用自有的CA证书给csr文件签名 openssl x509 -req -sha256 -days 365 -in server.csr -CA CA.crt -CAkey CA.key -CAcreateserial -out server.crt

转成c#能使用的证书,用c#写web api做后台其实格式和java使用的.p12是一样的只是后缀名不同。(此文件包含了私钥和证书),我这里设置了密码"123" openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt

可改成后缀名cer,AFNetworking可识别的。 openssl x509 -in server.crt -outform der -out "server.der"

NOTE:CA验证大概原理是,他会给你的证书公钥、机构、等信息用CA私钥加密然后生成签名放在返回给你的已经签名过的证书里。

AFNetworking与服务端的代码配置

AFHTTPSessionManager配置代码如下

1
2
3
4
5
6
7
8
if (_sessionManager == nil) {
        _sessionManager = [AFHTTPSessionManager manager];
        _sessionManager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
        _sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]]];
_sessionManager.securityPolicy = securityPolicy;
_sessionManager.securityPolicy.allowInvalidCertificates = YES;//不验证证书有效性
_sessionManager.securityPolicy.validatesDomainName = NO;//不验证域名

把上面准备好的证书,放到APP的bundle里面,和web api项目根目录里面,服务端代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var config = new ConfigurationBuilder()
                .AddCommandLine(args)
                .AddEnvironmentVariables(prefix: "ASPNETCORE_")
                .Build();

            var host = new WebHostBuilder()
                .UseConfiguration(config)
                .UseKestrel(options =>
                {
                    HttpsConnectionFilterOptions httpsoptions = new    HttpsConnectionFilterOptions();
                    httpsoptions.ServerCertificate = new X509Certificate2("certificate.pfx", "123");;
                    httpsoptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
                    httpsoptions.CheckCertificateRevocation = false;
                    options.UseHttps(httpsoptions);
                })
                .UseUrls("http://192.168.1.89:5000", "https://192.168.1.89:5001")
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();

启动服务,然后客户端访问,发现可以正常访问。

如果需要验证证书的有效性,可以使用CA证书。通过iOS模拟器,直接拖CA证书文件到模拟器界面上然后安装就可以了。客户端代码修改

1
//_sessionManager.securityPolicy.allowInvalidCertificates = YES;//注释掉,模式是不允许无效证书的

服务端代码修改

1
httpsoptions.ServerCertificate = new X509Certificate2("server.pfx", "123");

然后把server.cer证书分别放到客户端和服务端项目里面,启动服务,客户端访问,发现访问成功。

相关概念

双向认证的大概步骤: 1. 客户端请求一个受保护的资源 2. 服务端发送它的证书到客户端 3. 如果验证成功,客户端发送它的证书到服务端 4. 服务端验证客户端证书。 5. 如果成功,服务端允许该客户端访问它的受保护的资源

NOTE:CA验证证书有效性的过程大概是,因为CA会用私钥签名证书,那么该证书的签名是用私钥加密的,当这个证书从服务端发送过来时,CA证书会用公钥去机密签名而得到证书的公钥,解不开就证明不是此CA颁发的证书,此证书验证无效。