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

NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];

除非它给出一个错误,如果证书是自签名的一个错误域=NSURLErrorDomain Code=-1202 UserInfo=0xd29930“不受信任的服务器证书”。有没有一种方法来设置它接受连接(就像在浏览器中你可以按accept)或一种方法来绕过它?


当前回答

如果你想继续使用sendSynchronousRequest,我在这个解决方案:

FailCertificateDelegate *fcd=[[FailCertificateDelegate alloc] init];

NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO];
[c setDelegateQueue:[[NSOperationQueue alloc] init]];
[c start];    
NSData *d=[fcd getData];

你可以在这里看到:Objective-C SSL同步连接

其他回答

有一个支持的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];
}

注意connection:didReceiveAuthenticationChallenge:可以将其消息发送给challenge。发送方(很久以后),在必要时向用户呈现对话框之后,等等。

由Nathan de Vries发布的category工作区将通过AppStore私有API检查,并且在你无法控制NSUrlConnection对象的情况下很有用。 一个例子是NSXMLParser,它将打开你提供的URL,但不公开NSURLRequest或NSURLConnection。

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

To complement the accepted answer, for much better security, you could add your server certificate or your own root CA certificate to keychain( https://stackoverflow.com/a/9941559/1432048), however doing this alone won't make NSURLConnection authenticate your self-signed server automatically. You still need to add the below code to your NSURLConnection delegate, it's copied from Apple sample code AdvancedURLConnections, and you need to add two files(Credentials.h, Credentials.m) from apple sample code to your projects.

- (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];
}

你必须使用NSURLConnectionDelegate来允许HTTPS连接iOS8有新的回调。

弃用:

connection:canAuthenticateAgainstProtectionSpace:
connection:didCancelAuthenticationChallenge:
connection:didReceiveAuthenticationChallenge:

相反,你需要声明:

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];

这不是我的功劳,但我发现这个真的很适合我的需要。shouldAllowSelfSignedCert是我的BOOL变量。只需添加到你的NSURLConnection委托,你应该是rockin快速绕过每个连接的基础上。

- (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;
}