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

关于在UIwebView中访问HTTPS站点的几种方法

2012-04-26 18:17 393 查看
这两天一直在研究如何用UIWebView访问HTTPS站点,试过很多方法,但都有这样那样的缺陷,下面简单分享一下,希望各位提点意见:

1。调用私有API

最简单,也最危险的方法,调用 setAllowsAnyHTTPSCertificate:forHost ,后果怎么样就不用我说了吧。

2. libCurl

这是一个开源项目,用C语言写的URL转换库,是基于于openssl的,可以支持目前大部分的URL,包括DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET 和 TFTP,而且用这个不会使用苹果禁止的私有API,所以可以顺利通过App Store的审核。 但是有一个问题,就是要自己编译libcurl和openssl
的两个静态库,其中的配置比较麻烦,不熟悉在unix环境下编译静态库的朋友们可能就会皱眉头了。这有两个链接,可以参考 :

http://www.therareair.com/2009/01/01/tutorial-how-to-compile-openssl-for-the-iphone/

http://www.yifeiyang.net/iphone-web-development-skills-of-the-article-5-https-server-using-libcurl-to-connect/

编译成功后,将libcurl引入工程,再加上下面这些代码,就可以顺利访问HTTPS站点了

/*************** 调用libcurl 访问HTTPS站点 ****************

const char *urlstring=[homeUrl cStringUsingEncoding:NSUTF8StringEncoding];

CURL *curl;

CURLcode res;

char* buffer;

int buflen=1024;

size_t* n;

curl = curl_easy_init();

if (curl) {

curl_easy_setopt(curl, CURLOPT_URL, "https://10.20.7.236/login.aspx?ReturnUrl=%2f");

//curl_easy_setopt(curl, CURLOPT_URL, urlstring);

curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);



res = curl_easy_perform(curl);



if (0 != res) {

fprintf(stderr, "curl error: %d\n", res);

}

//res=curl_easy_recv(curl, buffer, buflen, n);

//printf("%s",buffer);

curl_easy_cleanup(curl);

}

*****************************************************/

通过联机调试在我的ipod上成功的访问到了HTTPS站点,在控制台中可以看到网页的内容,剩下的就是如何把这些内容存到一个字符数组里面,再通过调用UIwebView的loadHTMLString方法,就可以显示内容了, 不过最后这一步我还没有找到方法,希望有兴趣的朋友可以帮我解决这个问题。

3。ASIHTTPRequest

这个开源项目也是流行很久了, 但是一般都是用来替代NSURLConnection,其实里面的功能还是挺强大的,只是对于HTTPS访问这一块我有点不太满意,

里面有一个方法,是可以直接忽略证书验证的,

disabling secure certificate validation

You may wish to use this for testing purposes if you have a self-signed secure certificate. I recommend purchasing a certificate from a trusted certificate authority and leaving certificate validation turned on for production applications.

[request setValidatesSecureCertificate:NO];

但是这样做有一点危险,如果是放在企业环境里部署的话,那外面的人都可以访问内部的网站了,SSL这一层就形同虚设。所以我又找了一下,发现他还有另一个方法,可以设置客户端的证书:

Client certificates support

If your server requires the use of client certificates, as of v1.8 it is now possible to send them with your request.

// Will send the certificate attached to the identity (identity is a SecIdentityRef)

[request setClientCertificateIdentity:identity];

// Add an additional certificate (where cert is a SecCertificateRef)

[request setClientCertificates:[NSArray arrayWithObject:(id)cert]];

There is a helper function in 'ClientCertificateTests.m' in the iPhone / iPad sample app that can create a SecIdentityRef from PKCS12 data (this function only works on iOS).

这个方法需要把p12文件放进工程里面,然后调用[ClientCertificateTest extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]; 来获取identity

,这个方法是这样的

+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data

{

OSStatus securityError = errSecSuccess;



NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"" forKey:(id)kSecImportExportPassphrase];



CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);



if (securityError == 0) {

CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);

const void *tempIdentity = NULL;

tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);

*outIdentity = (SecIdentityRef)tempIdentity;

const void *tempTrust = NULL;

tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);

*outTrust = (SecTrustRef)tempTrust;

} else {

NSLog(@"Failed with error code %d",(int)securityError);

return NO;

}

return YES;

}

这个方法需要引用到Security.framework这个框架(我第一次没有引用,结果报错,我想官方的东西怎么还有错呢,郁闷了好久才发现是这个框架没有引用,晕死)。之后应该就是通过[ASIHTTPRequest startSynchronous] 可以访问HTTPS网站了。 为什么说是应该呢? 因为我也没有试出来,呵呵 ```可能是证书的问题,我在extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data 这个方法里获取到的securityError
为-26275 ,在网上找了半天也没找出个结果来,所以也只能暂时搁置了。

-(void) viewHomePage{

NSURL *url=[NSURL URLWithString:homeUrl];



NSBundle *bundle = [NSBundle mainBundle]; //取得mainBundle

NSString *plistPath = [bundle pathForResource:@"Root" ofType:@"plist"]; //取得文件路径

// 或可以写成

// NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"文件名" ofType:@"plist"];

//读取到一个NSDictionary

NSArray *array=[[NSArray alloc]initWithContentsOfFile:plistPath];



NSDictionary *dictionary = [array objectAtIndex:1];

NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];

[defaults registerDefaults:dictionary];



BOOL needAuthentication=[defaults boolForKey:@"needAuth"];



SecIdentityRef identity = NULL;

SecTrustRef trust = NULL;

NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ioa.bingosoft.net" ofType:@"pfx"]];

[SenchaShellViewController extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];



//****************** 调用 ASIHTTPRequest 访问HTTPS站点 ****************

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];



[request setClientCertificateIdentity:identity];

//[request setValidatesSecureCertificate:NO];

//[request startSynchronous];

[request setValidatesSecureCertificate:needAuthentication];

[request startSynchronous];



NSError *error = [request error];

if (!error) {

[self.viewer loadHTMLString:[request responseString] baseURL: [request url]];

}

else {

NSLog(@"Error: %@", error );

}



4。 官方API

最后一个是官方的API, 按理说这个应该放到最前面,因为是官方的嘛,但是实际上我一次都没有试成功过,所以有点怀疑他的真实性,不过也许有人成功了,所以也拿上来讨论一下。

简单来说通过NSurlconnection的这两个委托方法来忽略认证,关于Certificate Authentication是有官方文档的,但是官方文档太长了,我没有心思看完,所以还没有深入研究下去。

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {

return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];

}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {

if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])

//if ([trustedHosts containsObject:challenge.protectionSpace.host])

[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]

forAuthenticationChallenge:challenge];



[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];

}
tmy132011-07-21 11:26
谢谢lz的分享。不过我不知道你这几个方法和uiwebview有什么联系?难道你只是想用uiwebview来显示页面?数据通过你上面所说的来获得?
fingerplay2011-07-26 21:07
嗯,跟UIWebView确实是没有太大关系,准确的来讲只是获取HTTPS请求的几种方式吧,可以通过这些方法跟HTTPS站点交互。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: