如何使用NSURLConnection连接SSL以获取不受信任的证书?

ero*_*ppa 299 https objective-c ssl-certificate ios app-transport-security

我有以下简单的代码连接到SSL网页

NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];
Run Code Online (Sandbox Code Playgroud)

如果证书是自签名的,那么它会出错.Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".有没有办法将它设置为接受连接(就像在浏览器中你可以按接受)或绕过它的方法?

小智 415

有一个支持的API来完成这个!将这样的内容添加到您的NSURLConnection委托:

- (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];
}
Run Code Online (Sandbox Code Playgroud)

请注意,connection:didReceiveAuthenticationChallenge:在必要时向用户显示对话框之后,可以稍后将其消息发送到challenge.sender(等等).

  • 从iOS 5.0和Mac OS X 10.6开始,这些方法现在被视为已弃用.应该使用` - (void)连接:(NSURLConnection*)连接willSendRequestForAuthenticationChallenge :( NSURLAuthenticationChallenge*)challenge`方法. (42认同)
  • 非常感谢,它完美无缺.如果您想接受任何https站点,只需删除两个ifs并仅在didReceiveAuthentificationChallenge回调中保留useCendential部分. (31认同)
  • 什么是trustedHosts,其中n如何定义对象 (19认同)
  • 这段代码效果很好.但请注意,拥有有效证书的全部意义在于防止中间人攻击.所以要注意,如果你使用这个代码,有人可以欺骗所谓的"可信主机".您仍然可以获得SSL的数据加密功能,但是您丢失了主机识别验证功能. (19认同)
  • Ameya,它将是NSString对象的NSArray.字符串是@"google.com"等主机名. (7认同)
  • 是的,但旧的方法仍将被称为"如果连接:willSendRequestForAuthenticationChallenge:未实现,则旧的,不推荐使用的方法连接:canAuthenticateAgainstProtectionSpace:,connection:didReceiveAuthenticationChallenge:和connection:didCancelAuthenticationChallenge:"而是被调用. (4认同)
  • 适用于NSURLConnection.对NSURLSession的任何建议? (4认同)
  • 只是想要在sendSynchronous类方法中调用这些委托方法.请参阅:[link](http://stackoverflow.com/questions/2679944/objective-c-ssl-synchronous-connection) (2认同)

Nat*_*ies 36

如果您不愿意(或无法)使用私有API,那么有一个名为ASIHTTPRequest的开源(BSD许可证)库,它提供了一个围绕较低级别的包装器CFNetwork APIs.他们最近推出了允许HTTPS connections-setValidatesSecureCertificate:API中使用自签名或不可信证书的功能.如果您不想引入整个库,可以使用源作为参考,自己实现相同的功能.

  • ASIHTTPRequest库开发已被放弃. (7认同)
  • 蒂姆,你可能会发现自己想要出于其他原因使用异步(比如能够显示进度条),除了最简单的请求外,我找到的就是我的方式.所以也许你应该立即实现Async并稍后节省麻烦. (2认同)

小智 33

理想情况下,应该只有两种情况,即iOS应用程序何时需要接受不受信任的证书.

方案A:您已连接到使用自签名证书的测试环境.

方案B:您HTTPS使用A代理流量MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.代理将返回由自签名CA签名的证书,以便代理能够捕获HTTPS流量.

生产主机不应该使用不受信任的证书显而易见的原因.

如果您需要让iOS模拟器接受不受信任的证书以进行测试,强烈建议您不要更改应用程序逻辑,以禁用NSURLConnectionAPI 提供的内置证书验证.如果应用程序在不删除此逻辑的情况下向公众发布,则它将容易受到中间人攻击.

为测试目的接受不受信任的证书的推荐方法是将签署证书的证书颁发机构(CA)证书导入iOS模拟器或iOS设备.我写了一篇快速博客文章,演示如何在iOS模拟器中执行此操作:

使用ios模拟器接受不受信任的证书


Nat*_*ies 12

NSURLRequest有一个名为的私有方法setAllowsAnyHTTPSCertificate:forHost:,它将完全按照您的意愿执行.您可以通过类别定义allowsAnyHTTPSCertificateForHost:方法NSURLRequest,并将其设置为返回YES您要覆盖的主机.


xia*_*ang 11

为了补充已接受的答案,为了更好的安全性,您可以将您的服务器证书或您自己的根CA证书添加到钥匙串(/sf/answers/695909161/),但是单独执行此操作不会使NSURLConnection自动验证您的自签名服务器.您仍然需要将以下代码添加到NSURLConnection委托中,它是从Apple示例代码AdvancedURLConnections复制的,您需要将两个文件(Credentials.h,Credentials.m)从apple示例代码添加到您的项目中.

- (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])

    OSStatus                err;
    NSURLProtectionSpace *  protectionSpace;
    SecTrustRef             trust;
    SecTrustResultType      trustResult;
    BOOL                    trusted;

    protectionSpace = [challenge protectionSpace];
    assert(protectionSpace != nil);

    trust = [protectionSpace serverTrust];
    assert(trust != NULL);
    err = SecTrustEvaluate(trust, &trustResult);
    trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));

    // If that fails, apply our certificates as anchors and see if that helps.
    //
    // It's perfectly acceptable to apply all of our certificates to the SecTrust
    // object, and let the SecTrust object sort out the mess.  Of course, this assumes
    // that the user trusts all certificates equally in all situations, which is implicit
    // in our user interface; you could provide a more sophisticated user interface
    // to allow the user to trust certain certificates for certain sites and so on).

    if ( ! trusted ) {
        err = SecTrustSetAnchorCertificates(trust, (CFArrayRef) [Credentials sharedCredentials].certificates);
        if (err == noErr) {
            err = SecTrustEvaluate(trust, &trustResult);
        }
        trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
    }
    if(trusted)
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}

[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Run Code Online (Sandbox Code Playgroud)


小智 10

我不能相信这一点,但我找到的这个对我的需求非常有用.shouldAllowSelfSignedCert是我的BOOL变量.只需添加到您的NSURLConnection代理,您应该摇滚以在每个连接的基础上快速绕过.

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space {
     if([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
          if(shouldAllowSelfSignedCert) {
               return YES; // Self-signed cert will be accepted
          } else {
               return NO;  // Self-signed cert will be rejected
          }
          // Note: it doesn't seem to matter what you return for a proper SSL cert
          //       only self-signed certs
     }
     // If no other authentication is required, return NO for everything else
     // Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
     return NO;
}
Run Code Online (Sandbox Code Playgroud)


joh*_*ieb 10

在iOS 9中,所有无效或自签名证书的SSL连接都将失败.这是iOS 9.0或更高版本以及OS X 10.11及更高版本中新的App Transport Security功能的默认行为.

您可以Info.plist通过在字典中设置NSAllowsArbitraryLoads为覆盖此行为.但是,我建议仅为测试目的覆盖此设置.YESNSAppTransportSecurity

在此输入图像描述

有关信息,请参阅应用交通运输技术说明这里.


小智 6

Nathan de Vries发布的类别解决方法将通过AppStore私有API检查,在您无法控制NSUrlConnection对象的情况下非常有用.一个例子是NSXMLParser打开你提供的URL,但不公开NSURLRequestNSURLConnection.

在iOS 4中,解决方法似乎仍然有效,但仅在设备上,模拟器不再调用该allowsAnyHTTPSCertificateForHost:方法.


ric*_*ira 6

您必须使用NSURLConnectionDelegate允许HTTPS连接,并且iOS8有新的回调.

推荐使用:

connection:canAuthenticateAgainstProtectionSpace:
connection:didCancelAuthenticationChallenge:
connection:didReceiveAuthenticationChallenge:
Run Code Online (Sandbox Code Playgroud)

相反,你需要声明:

connectionShouldUseCredentialStorage: - 发送以确定URL加载程序是否应使用凭据存储来验证连接.

connection:willSendRequestForAuthenticationChallenge: - 告知代理该连接将发送身份验证质询请求.

有了willSendRequestForAuthenticationChallenge你可以使用challenge像你过时方法,比如做:

// Trusting and not trusting connection to host: Self-signed certificate
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

257025 次

最近记录:

8 年,11 月 前