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を押すことができます)。
これを実現するためのサポートされている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にメッセージを送信できます。
プライベートAPIを使用したくない(または使用できない)場合は、 ASIHTTPRequest というオープンソース(BSDライセンス)のライブラリがあり、これが低レベルのCFNetwork APIs
のラッパーを提供します。彼らは最近、HTTPS connections
APIで自己署名または信頼できない証明書を使用して-setValidatesSecureCertificate:
を許可する機能を紹介しました。ライブラリ全体を取り込まないのであれば、自分自身で同じ機能を実装するための参照としてソースを使用することができます。
理想的には、iOSアプリケーションが信頼できない証明書を受け入れる必要があるのは2つのシナリオだけであるべきです。
シナリオA:自己署名証明書を使用しているテスト環境に接続しています。
シナリオB:MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.
を使用してHTTPS
トラフィックをプロキシ処理している場合プロキシーがHTTPS
トラフィックをキャプチャーできるように、プロキシーは自己署名CAが署名した証明書を返します。
本番ホストは 明白な理由 で信頼できない証明書を使用してはいけません。
テスト目的でiOSシミュレータに信頼できない証明書を許可する必要がある場合は、NSURLConnection
APIによって提供される組み込みの証明書検証を無効にするためにアプリケーションロジックを変更しないことを強くお勧めします。このロジックを削除せずにアプリケーションが一般に公開されると、中間者攻撃を受けやすくなります。
テスト目的で信頼されていない証明書を受け入れる推奨される方法は、証明書に署名した認証局(CA)証明書をiOSシミュレータまたはiOSデバイスにインポートすることです。私はこれをどのように行うかを示す簡単なブログ記事を書きました。
iosシミュレータを使用して信頼できない証明書を受け入れる
NSURLRequest
はsetAllowsAnyHTTPSCertificate:forHost:
と呼ばれるプライベートメソッドを持っています。カテゴリを介してNSURLRequest
のallowsAnyHTTPSCertificateForHost:
メソッドを定義し、上書きしたいホストに対してYES
を返すように設定することができます。
受け入れられた答えを補完するために、はるかに高いセキュリティのために、あなたはあなたのサーバー証明書またはあなた自身のルート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];
}
私はこれを信用していません しかしこれは私が見つけたものです 私のニーズには本当にうまくいきました。 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;
}
IOS 9では、すべての無効な証明書または自己署名証明書についてSSL接続が失敗します。これは、iOS 9.0以降およびOS X 10.11以降での新しい App Transport Security 機能のデフォルトの動作です。
NSAllowsArbitraryLoads
辞書でYES
をNSAppTransportSecurity
に設定することで、Info.plist
でこの動作をオーバーライドできます。 ただし、テスト目的でのみこの設定を上書きすることをお勧めします。
詳しくは、App Transport Technote こちら を参照してください。
Nathan de Vriesによって投稿されたカテゴリの回避策はAppStoreプライベートAPIチェックに合格するでしょう、そしてあなたがNSUrlConnection
オブジェクトの制御を持たない場合に役に立ちます。 1つの例はNSXMLParser
です。これはあなたが提供するURLを開きますが、NSURLRequest
やNSURLConnection
は公開しません。
IOS 4では、この回避策はまだ機能するようですが、デバイス上でのみ、SimulatorはallowsAnyHTTPSCertificateForHost:
メソッドを呼び出しません。
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];
自己生成した証明書(および無料の証明書を取得する方法 - Cocoanetics の下のコメントを参照)に対して適切に認証できるようにするためのGistコードを投稿しました。
私のコードはここにあります github
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同期接続
と 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);
}];
あなたはこのコードを使用することができます
-(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