nginx与ios实现https双向认证

服务端配置

nginx关键配置如下:

listen       443;
server_name  localhost;
ssl on;
ssl_certificate      /usr/local/opt/nginx/certificates/server.cer;
ssl_certificate_key  /usr/local/opt/nginx/certificates/server.key.pem;
ssl_client_certificate /usr/local/opt/nginx/certificates/ca.cer;
ssl_verify_client    on;

ssl开启https

ssl_certificate是服务端证书的路径,ssl_certificate_key是服务端私钥的路径

ssl_verify_client是配置双向认证(client certificate)

ssl_client_certificate是签发客户端证书的根证书

为什么是根证书,因为可以签发很多客户端证书,只要是由该根证书签发的,服务端都视为认证通过

配置完成以后,一般需要把80端口的http请求跳转到443端口,否则用户可以通过80端口以http方式访问,就失去了安全保护的意义

客户端代码

在网上找了很多ios client certificate的帖子,要么是代码不全,要么是很老的帖子,还是用的NSURLConnection,delegate method都deprecated了,最后找了一个代码片段,改了一下

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

NSURL *url = [NSURL URLWithString:@"https://localhost/svc/portal/setting"];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:30];
[request setHTTPMethod:@"GET"];

NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", message);
}];

[task resume];

上面的代码片段,是用NSURLSessionDataTask发起https请求。在ssl握手阶段,会调用2次下面的delegate method

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSString *method = challenge.protectionSpace.authenticationMethod;
    NSLog(@"%@", method);

    if([method isEqualToString:NSURLAuthenticationMethodServerTrust]){

        NSString *host = challenge.protectionSpace.host;
        NSLog(@"%@", host);

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        return;
    }

    NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
    CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);
    SecIdentityRef identity;

    // 读取p12证书中的内容
    OSStatus result = [self extractP12Data:inPKCS12Data toIdentity:&identity];
    if(result != errSecSuccess){
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        return;
    }

    SecCertificateRef certificate = NULL;
    SecIdentityCopyCertificate (identity, &certificate);

    const void *certs[] = {certificate};
    CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);

    NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)CFBridgingRelease(certArray) persistence:NSURLCredentialPersistencePermanent];

    completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}

-(OSStatus) extractP12Data:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {

    OSStatus securityError = errSecSuccess;

    CFStringRef password = CFSTR("the_password");
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };

    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inP12Data, options, &items);

    if (securityError == 0) {
        CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
        *identity = (SecIdentityRef)tempIdentity;
    }

    if (options) {
        CFRelease(options);
    }

    return securityError;
}

上面的代码片段,即拷即用,希望能有所帮助。这个方法会被调用2次,第一次是ios app验证server的阶段,第二次是server验证ios app的阶段,即client certificate。关键是每个阶段的校验完成以后,要调用completionHandler方法。网上的大部分帖子都是

[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];

这行代码是无效的

nginx与ios实现https双向认证

时间: 2024-10-10 23:30:25

nginx与ios实现https双向认证的相关文章

HTTPS 双向认证构建移动设备安全体系

HTTPS 双向认证构建移动设备安全体系 对于一些高安全性要求的企业内项目,我们有时希望能够对客户端进行验证.这个时候我们可以使用Https的双向认证机制来实现这个功能. 单向认证:保证server是真的,通道是安全的(对称密钥):双向认证:保证client和server是真的,通道是安全的(对称密钥): 要实现这么一个完整的安全体系,需要一个CA或者openssl自建CA来管理签发客户端证书.作为项目要求的场景可能是这样的,一个前端网站专门用于签发证书,通过电子邮件发送下载客户端证书邮件到移动

rails+apache2+passenger+ssl实现https双向认证通信

rails+apache2+passenger+ssl实现https双向认证通信 环境: 系统:Centos7 服务器:apache(httpd) 2.4.6 制作工具:openssl 1.0.1 Rails版本 :4.1.6 准备工作: 安装apache和openssl #yum install  httpd  httpd-devel httpd-tools #yum install openssl 安张mod_ssl #yum install mod_ssl 一.创建根证书 1创建CA私钥

利用tomcat服务器配置https双向认证

首先请保证已经安装好jdk,并且环境变量以及配置好了 第一步.为服务器生成证书: 使用toolkey为tomcat生成证书,假定目标机器的域名为localhost,使用如下命令生成:keytool –genkey –v –aliaslocalhost_server RSA –keystore localhost_server.store  –validity 36500 第二步.为客户端生成证书: 为浏览器生成证书,以便让服务器来验证它.为了能保证证书顺利导入至IE和Firefox,证书格式应该

tomcat https双向认证

没啥可写的,直接看这些博文吧... 注:server.xml 双向认证 注意得配:truststoreFile,单向不用 浏览器客户端p12证书,需要添加到服务器的jks文件中. http://www.blogjava.net/stevenjohn/archive/2012/08/22/385989.html http://www.360doc.com/content/10/0401/23/633992_21237818.shtml http://www.blogjava.net/stevenj

Android Https双向认证 + GRPC

keywords:android https 双向认证android GRPC https 双向认证 ManagedChannel channel = OkHttpChannelBuilder.forAddress("xxx",yyy) .overrideAuthority("zzz") .sslSocketFactory(sslFactory) .build(); 1.千万不要像官网案例那样设置setPlaintext(true),这个是设置明文,我们用的是密文

tomcat构建HTTPS双向认证

第一步:为服务器生成证书 # keytool -genkey -alias tomcat -keyalg RSA -keystore /usr/local/ac/web/tomcat.keystore -validity 36500 (参数简要说明:"/etc/tomcat.keystore"含义是将证书文件保存在路径/usr/local/ac/web/下,证书文件名称是tomcat.keystore :"-validity 36500"含义是证书有效期,36500

ASIHTTPRequest实现https双向认证请求

什么是双向认证呢?简而言之,就是服务器端对请求它的客户端要进行身份验证,客户端对自己所请求的服务器也会做身份验证.服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信.客户端如果发现服务端为不可信任的,那么也中止通信. 双向认证的算法理论是RSA,(点击此处了解RSA算法原理). 双向认证具体又是通过安全证书的方式来实现的,安全证书可用openssl或java程序来生成,用于双向认证的安全证书中保存了密钥对,证书颁发机构信 息,签名信息,签名算法,颁发对象,有效期等信息.双向认证中

AFNetWorking https 双向认证

客户端验证服务端证书: 需要http配置路径需要域名 1:先项目中倒入服务端证书 sever.cer, 2.然后设置 AFSecurityPolicy self.manager = [AFHTTPRequestOperationManager manager]; self.manager.responseSerializer = [[AFHTTPResponseSerializer alloc] init]; [self.manager.requestSerializer setValue:@"

https双向认证时证书签发和配置

1.生成CA自签文件 1.1  在openssl-0.9.8h-1-bin\bin进入cmd窗口 或者 cmd窗口路径到openssl-0.9.8h-1-bin\bin下 1.2 ras的秘钥长度:2048 存放ca公钥证书的路径:D:/cert_test/root_ca/ca_cert.pem 证书的有效期(天): 3650 根证书配置文件:D:/jx_cert/conf/gen_ca.conf 根据自己的需要调整配置文件的私钥证书证书存放路径,颁发者名称等 openssl req -x509