web-dev-qa-db-ja.com

信頼されていない証明書のためにNSURLConnectionを使用してSSLに接続する方法は?

SSL Webページに接続するための以下の簡単なコードがあります。

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

証明書が自己署名された証明書である場合はエラーになります。Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".接続を受け入れるように設定する方法はありますか(ブラウザの場合のように、acceptを押すことができます)。

297
erotsppa

これを実現するためのサポートされている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.senderにメッセージを送信できます。

414

プライベートAPIを使用したくない(または使用できない)場合は、 ASIHTTPRequest というオープンソース(BSDライセンス)のライブラリがあり、これが低レベルのCFNetwork APIsのラッパーを提供します。彼らは最近、HTTPS connections APIで自己署名または信頼できない証明書を使用して-setValidatesSecureCertificate:を許可する機能を紹介しました。ライブラリ全体を取り込まないのであれば、自分自身で同じ機能を実装するための参照としてソースを使用することができます。

36
Nathan de Vries

理想的には、iOSアプリケーションが信頼できない証明書を受け入れる必要があるのは2つのシナリオだけであるべきです。

シナリオA:自己署名証明書を使用しているテスト環境に接続しています。

シナリオB:MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.を使用してHTTPSトラフィックをプロキシ処理している場合プロキシーがHTTPSトラフィックをキャプチャーできるように、プロキシーは自己署名CAが署名した証明書を返します。

本番ホストは 明白な理由 で信頼できない証明書を使用してはいけません。

テスト目的でiOSシミュレータに信頼できない証明書を許可する必要がある場合は、NSURLConnection APIによって提供される組み込みの証明書検証を無効にするためにアプリケーションロジックを変更しないことを強くお勧めします。このロジックを削除せずにアプリケーションが一般に公開されると、中間者攻撃を受けやすくなります。

テスト目的で信頼されていない証明書を受け入れる推奨される方法は、証明書に署名した認証局(CA)証明書をiOSシミュレータまたはiOSデバイスにインポートすることです。私はこれをどのように行うかを示す簡単なブログ記事を書きました。

iosシミュレータを使用して信頼できない証明書を受け入れる

33
user890103

NSURLRequestsetAllowsAnyHTTPSCertificate:forHost:と呼ばれるプライベートメソッドを持っています。カテゴリを介してNSURLRequestallowsAnyHTTPSCertificateForHost:メソッドを定義し、上書きしたいホストに対してYESを返すように設定することができます。

12
Nathan de Vries

受け入れられた答えを補完するために、はるかに高いセキュリティのために、あなたはあなたのサーバー証明書またはあなた自身のルートCA証明書をキーチェーンに追加することができます( https://stackoverflow.com/a/9941559/1432048 )ただし、これを単独で行ってもNSURLConnectionは自己署名サーバーを自動的に認証しません。あなたはまだあなたのNSURLConnectionデリゲートに以下のコードを追加する必要があります、それはアップルのサンプルコード AdvancedURLConnections からコピーされます、そしてあなたは2つのファイル(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];
}
11
xiang

私はこれを信用していません しかしこれは私が見つけたものです 私のニーズには本当にうまくいきました。 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;
}
10
Ryna

IOS 9では、すべての無効な証明書または自己署名証明書についてSSL接続が失敗します。これは、iOS 9.0以降およびOS X 10.11以降での新しい App Transport Security 機能のデフォルトの動作です。

NSAllowsArbitraryLoads辞書でYESNSAppTransportSecurityに設定することで、Info.plistでこの動作をオーバーライドできます。 ただし、テスト目的でのみこの設定を上書きすることをお勧めします。

enter image description here

詳しくは、App Transport Technote こちら を参照してください。

10
johnnieb

Nathan de Vriesによって投稿されたカテゴリの回避策はAppStoreプライベートAPIチェックに合格するでしょう、そしてあなたがNSUrlConnectionオブジェクトの制御を持たない場合に役に立ちます。 1つの例はNSXMLParserです。これはあなたが提供するURLを開きますが、NSURLRequestNSURLConnectionは公開しません。

IOS 4では、この回避策はまだ機能するようですが、デバイス上でのみ、SimulatorはallowsAnyHTTPSCertificateForHost:メソッドを呼び出しません。

6
Alex Suzuki

HTTPS接続を許可するにはNSURLConnectionDelegateを使用する必要があり、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];
6
ricardopereira

自己生成した証明書(および無料の証明書を取得する方法 - Cocoanetics の下のコメントを参照)に対して適切に認証できるようにするためのGistコードを投稿しました。

私のコードはここにあります github

3
David H

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同期接続

2
jgorozco

AFNetworking 私は正常にhttpsのWebサービスを以下のコードで消費しました、

NSString *aStrServerUrl = WS_URL;

// Initialize AFHTTPRequestOperationManager...
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
manager.securityPolicy.allowInvalidCertificates = YES; 
[manager POST:aStrServerUrl parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
    successBlock(operation, responseObject);

} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
    errorBlock(operation, error);
}];
1
cjd

あなたはこのコードを使用することができます

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
     if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust)
     {
         [[challenge sender] useCredential:[NSURLCredential credentialForTrust:[[challenge protectionSpace] serverTrust]] forAuthenticationChallenge:challenge];
     }
}

これらの非推奨メソッドの代わりに-connection:willSendRequestForAuthenticationChallenge:を使用してください。

非推奨:

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace  
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
-(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
0
Vaibhav Sharma