您的位置:首页 > 理论基础 > 计算机网络

关于ios项目绕过证书访问https

2016-06-24 20:45 441 查看
听说苹果发布了声明,将于年底将所有iOS应用的http访问强制改为https访问。个人认为这是个好事,启用HTTPS网络连接之后,数据传输的安全性将大幅提示,不容易被黑客拦截破译。

所以得跟上形势不是,这也许就是程序员的无奈,相当一个不过是的好程序员就得不断的学习新的知识。下面就是我用NSURLSession封装好的数据请求类。

说明:请求方法结合了MD5加密,大家看代码的时候注意看NSURLSessionTaskDelegate代理方法即可

AsyncNetWorkRequest.h 中

#import <Foundation/Foundation.h>

@interface AsyncNetWorkRequest : NSObject

// 定义block块属性
// 网络请求成功
@property (nonatomic, copy) void(^successBlock)(NSData *data);

// 网络请求失败
@property (nonatomic, copy) void(^errorBlock)(NSError *error);

+ (instancetype)startRequestDataWithURLStr:(NSString *)str parameter:(NSDictionary *)parameter requestType:(NSString *)type SucessBlock:(void (^)(NSData *data))sucessBlock ErrorBlock:(void (^)(NSError *error))errorBlock;
+
@end


AsyncNetWorkRequest.m 中

#import "AsyncNetWorkRequest.h"
#import "MD5Encryption.h"

@interface AsyncNetWorkRequest () <NSURLSessionTaskDelegate>

@end

@implementation AsyncNetWorkRequest

- (instancetype)init {
self = [super init];
if (self) {

}
return self;
}

// 对外数据请求类
+ (instancetype)startRequestDataWithURLStr:(NSString *)str parameter:(NSDictionary *)parameter requestType:(NSString *)type SucessBlock:(void (^)(NSData *data))sucessBlock ErrorBlock:(void (^)(NSError *error))errorBlock
{
AsyncNetWorkRequest *async = [[AsyncNetWorkRequest alloc] init];

async.successBlock = sucessBlock;
async.errorBlock = errorBlock;

// 获取加密后的数据请求字符串
NSString *urlString = [MD5Encryption startMD5EncryptionWithParameters:parameter URLString:str];
NSLog(@"打印数据请求字符串 %@", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

//  get请求
if ([type isEqualToString:@"GET"]) {
[async requestGETWithRequest:request Async:async];
}
// post请求
else {
// 用 ?分割 取出要上传的数据。
NSArray *array = [urlString componentsSeparatedByString:@"?"];
NSString *stringBody = array[1];
// 将上传数据转化为data
NSData *bodyData = [stringBody dataUsingEncoding:NSUTF8StringEncoding];
NSURL *urlPost = [NSURL URLWithString:str];
NSMutableURLRequest *requestPost = [NSMutableURLRequest requestWithURL:urlPost];
[async requestPOSTWithRequest:requestPost Async:async BodyData:bodyData];
}
return async;
}

#pragma mark - post请求
- (void)requestPOSTWithRequest:(NSMutableURLRequest *)request Async:(AsyncNetWorkRequest *)async BodyData:(NSData *)bodyData
{
request.HTTPMethod = @"POST";
request.HTTPBody = bodyData;

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (error == nil) {
NSLog(@"POST请求成功");
async.successBlock(data);

}
else {
NSLog(@"POST请求失败");
async.errorBlock(error);
}
}];
[task resume];

}

#pragma mark - get请求
- (void)requestGETWithRequest:(NSMutableURLRequest *)request Async:(AsyncNetWorkRequest *)async
{
request.HTTPMethod = @"GET";
// 创建会话
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.TLSMaximumSupportedProtocol = kTLSProtocol1;

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

NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (error == nil) {
NSLog(@"GET数据请求成功");
async.successBlock(data);
}

else {
NSLog(@"GET数据请求失败 %@", [error description]);
async.errorBlock(error);
}
}];
[dataTask resume];

}

#if 1 - 这是第一种写法
// ios项目绕过证书访问https程序,当你向服务器请求时,服务器需要证书时会走下面的方法
- (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;
}

#endif

#if 0 - 这是第二种写法
#pragma mark - ios项目绕过证书访问https程序,当向服务端请求数据时,会通过该方法进行证书验证
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{

if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {

NSLog(@"服务端证书认证");

SecTrustRef servertrust = challenge.protectionSpace.serverTrust;
SecCertificateRef certi= SecTrustGetCertificateAtIndex(servertrust, 0);
NSData *certidata = CFBridgingRelease(CFBridgingRetain(CFBridgingRelease(SecCertificateCopyData(certi))));
NSString *path = [[NSBundle mainBundle] pathForResource:@"tomcat_server" ofType:@"cer"];
NSData *localCertiData = [NSData dataWithContentsOfFile:path];

if ([certidata isEqualToData:localCertiData]) {

NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:servertrust];

[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

}

else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
NSLog(@"服务端认证失败");
}
}

}

#endif

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: