iOS内置证书,校验https请求

有些情况处于安全的考虑需要https请求,但是为了防止域名解析很多情况下会使用IP进行访问。一般的服务不会针对IP去申请证书,所以我们可以自己实现ssl登录过程,保证请求的安全性。

一.首先需要自己本地生成ssl证书以及搭建一个本地服务

Mac apache本地配置ssl证书 及 iOS OTA部署: http://www.jianshu.com/p/bd016015efe7

生成的crt转换成cer的方法

openssl x509 -in test.crt -out test.cer -outform der

二.实现代码

初始化NSURLSession,将证书导入对应的xcode项目中

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.timeoutIntervalForRequest = 120;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                 delegate:self
                                            delegateQueue:[[NSOperationQueue alloc] init]];

生成的ssl证书需要设置ip,而且校验的时候也会去校验这个ip。但是更多情况下是不去校验这个ip的,因为代码内部可能只有一个证书,但是服务可能会有多套部署,如果去校验ip,会限制服务的扩展(很多项目都会做自己的DNS策略,ip经常会改变)。

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
    NSString *host = challenge.protectionSpace.host;
    BOOL isIp = [self _isIp:host];
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if (isIp) {
            // Get
            NSData *certData =[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"]];
            if (certData) {
                SecTrustRef trust = [[challenge protectionSpace] serverTrust];

                NSMutableArray *policies = [NSMutableArray array];          //如果需要校验IP,需要把下面的注释打开,把下面X509这段代码注释掉          //[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
                [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
                SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies);

                SecCertificateRef rootcert = SecCertificateCreateWithData(kCFAllocatorDefault,CFBridgingRetain(certData));
                const void *array[1] = { rootcert };
                CFArrayRef certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
                int err;
                SecTrustResultType trustResult = 0;
                err = SecTrustSetAnchorCertificates(trust, certs);
                if (err == noErr) {
                    err = SecTrustEvaluate(trust,&trustResult);
                }
                BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
                if (!trusted) {
                    NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ;
                    completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
                } else {
                    //如果校验失败了,就校验一下证书数据,一般不建议走这段逻辑,因为不能够保证服务是否安全
                    NSMutableArray *pinnedCertificates = [NSMutableArray array];
                    [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData)];
                    SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)pinnedCertificates);

                    NSArray *serverCertificates = [self _certificateTrustChainForServerTrust:trust];

                    for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                        if ([certData isEqualToData:trustChainCertificate]) {
                            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ;
                            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
                        }
                    }
                }
            }
        } else {
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        }
    }
}

- (BOOL)_isIp:(NSString*)aHost
{
    NSString *regex = @"((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];

    return [pred evaluateWithObject:aHost];
}

- (NSArray *)_certificateTrustChainForServerTrust:(SecTrustRef)serverTrust
{
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];

    for (CFIndex i = 0; i < certificateCount; i++) {
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
        [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
    }

    return [NSArray arrayWithArray:trustChain];
}

https请求构建

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://127.0.0.1:443/index.html"]];

    NSURLSessionDataTask *task = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        completionHandler(((NSHTTPURLResponse*)response).statusCode, data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : nil, error);
    }];

    [task resume];

网上的例子有很多,但是很多没有考虑不校验IP的场景。希望本文能够给大家一个参考

时间: 2024-11-06 00:53:17

iOS内置证书,校验https请求的相关文章

AFNetWorking3.0使用 自签名证书的https请求

前几日,项目组出于安全角度的考虑,要求项目中的请求使用https请求,因为是企业内部使用的app,因此使用了自签名的证书,而自签名的证书是不受信任的,所以我们就需要自己来做证书的验证,包括服务器验证客户端的证书和我们要信任服务器的证书,SSL双向认证的原理我这里就不赘述了,这里提供两篇博客 iOS安全系列之一:HTTPS: http://oncenote.com/2014/10/21/Security-1-HTTPS/ iOS安全系列之二:HTTPS进阶: http://oncenote.com

iOS使用自签名证书实现HTTPS请求

由于苹果规定2017年1月1日以后,所有APP都要使用HTTPS进行网络请求,否则无法上架,因此研究了一下在iOS中使用HTTPS请求的实现.相信大家对HTTPS都或多或少有些了解,这里我就不再介绍了,主要功能就是将传输的报文进行加密,提高安全性. 1.证书准备 证书分为两种,一种是花钱向认证的机构购买的证书,服务端如果使用的是这类证书的话,那一般客户端不需要做什么,用HTTPS进行请求就行了,苹果内置了那些受信任的根证书的.另一种是自己制作的证书,使用这类证书的话是不受信任的(当然也不用花钱买

app version updates must utilize the iOS built-in update mechanism(app的更新必须用iOS内置的更新机制)

今天有一个app审核被拒了,提示app里面包括了一个更新按钮,而app的更新必须用IOS的内置更新机制,而不是app里面含有更新视图 苹果的审核规则随时都会变,好吧,那就去掉了,重新打包上传审核

Mac使用Charles抓取ios手机APP中的https请求

1.配置Http代理 Port为监听端口号,默认为8888,勾选Enable transparent HTTP proxying,接着勾选SOCKS proxy,可以监听Socks请求 2.安装Charles Root Certificate,路径为Help->SSL Proxying ->InstallCharles Root Certificate 3.安装后在钥匙串中会有一条未信任的证书,双击该证书 4.跳转到该证书的设置,修改到如图 4.配置SSL代理,Proxy->SSL Pr

ios项目绕过证书访问https程序

如果是单个的webview或者request请求,在请求的文件h中直接实现NSURLConnectionDelegate,并在m中添加下列实现下列两个方法: C代码   - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { return [protectionSpace.authenticati

iOS内置音频

Predefined soundsThere are some predefined system sounds, for the system sound ID in the range 1000 to 2000 (decimal), as shown below (from 2.0 to 5.0 beta). The system sounds are all stored in /System/Library/Audio/UISounds/. Sound IDFile name (iPho

nginx内置变量

今天在整理nginx的rewrite规则,发现遇到许多关于nginx内置变量的判断,所以此处将nginx的内置变量温习一遍······ nginx支持的所有内置变量: $arg_name 请求中的的参数名,即"?"后面的arg_name=arg_value形式的arg_name $args 请求中的参数值 $binary_remote_addr 客户端地址的二进制形式, 固定长度为4个字节 $body_bytes_sent 传输给客户端的字节数,响应头不计算在内:这个变量和Apache

nginx内置变量 大全

nginx内置变量 内置变量存放在  ngx_http_core_module 模块中,变量的命名方式和apache 服务器变量是一致的.总而言之,这些变量代表着客户端请求头的内容,例如$http_user_agent, $http_cookie, 等等.下面是nginx支持的所有内置变量: $arg_name请求中的的参数名,即"?"后面的arg_name=arg_value形式的arg_name $args请求中的参数值 $binary_remote_addr客户端地址的二进制形式

fiddler抓包HTTPS请求

fiddler抓包HTTPS请求 标签: fiddlerhttps抓包 2016-03-29 21:24 23293人阅读 评论(2) 收藏 举报  分类: 不登高山不知天之高也(1)  版权声明:本文为高绍臣原创文章,转载请注明出处,本文博客地址:http://blog.csdn.net/gaoshaochen. 目录(?)[-] fiddler抓包HTTPS请求 教程开始 安装fiddler 配置fiddler 配置手机 抓包截图 让我们想想 fiddler抓包HTTPS请求 跟着教程来,保