신뢰할 수없는 인증서에 대해 NSURLConnection을 사용하여 SSL에 연결하는 방법은 무엇입니까?
SSL 웹 페이지에 연결하는 다음과 같은 간단한 코드가 있습니다.
NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];
인증서가 자체 서명 된 인증서 인 경우 오류가 발생하는 것을 제외하고 Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".
어쨌든 (브라우저에서 수락을 누를 수있는 것처럼) 연결을 수락하도록 설정하거나 우회하는 방법이 있습니까?
이를 위해 지원되는 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
자체 서명 또는 신뢰할 수없는 인증서를 -setValidatesSecureCertificate:
API 와 함께 사용할 수있는 기능을 도입했습니다 . 전체 라이브러리를 가져 오지 않으려면 소스를 동일한 기능을 직접 구현하기위한 참조로 사용할 수 있습니다.
이상적으로, iOS 애플리케이션이 신뢰할 수없는 인증서를 승인해야하는 경우는 두 가지 시나리오 만 있어야합니다.
시나리오 A : 자체 서명 된 인증서를 사용하는 테스트 환경에 연결되어 있습니다.
시나리오 B : 프록시를 HTTPS
사용하여 트래픽을 MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.
프록시 하는 중 프록시가 자체 서명 된 CA에서 서명 한 인증서를 프록시가 반환하므로 프록시가 HTTPS
트래픽 을 캡처 할 수 있습니다.
프로덕션 호스트는 확실한 이유로 신뢰할 수없는 인증서를 사용해서는 안됩니다 .
테스트 목적으로 iOS 시뮬레이터가 신뢰할 수없는 인증서를 수락하도록해야하는 경우 NSURLConnection
API에서 제공하는 기본 제공 인증서 유효성 검사를 비활성화하기 위해 응용 프로그램 논리를 변경하지 않는 것이 좋습니다 . 이 논리를 제거하지 않고 응용 프로그램을 일반에 공개하면 중간자 (man-in-the-middle) 공격에 취약합니다.
테스트 목적으로 신뢰할 수없는 인증서를 수락하는 권장 방법은 인증서에 서명 한 인증 기관 (CA) 인증서를 iOS 시뮬레이터 또는 iOS 장치로 가져 오는 것입니다. iOS 시뮬레이터 에서이 작업을 수행하는 방법을 보여주는 빠른 블로그 게시물을 작성했습니다.
iOS 시뮬레이터를 사용하여 신뢰할 수없는 인증서 수락
NSURLRequest
라는 개인 메소드가 있으며 setAllowsAnyHTTPSCertificate:forHost:
원하는 것을 정확하게 수행합니다. 범주 allowsAnyHTTPSCertificateForHost:
를 NSURLRequest
통해 메서드를 정의하고 YES
재정의하려는 호스트에 대해 반환하도록 설정할 수 있습니다.
허용 된 답변을 보완하기 위해 훨씬 나은 보안을 위해 서버 인증서 또는 자체 루트 CA 인증서를 키 체인에 추가 할 수 있지만 ( https://stackoverflow.com/a/9941559/1432048 ) NSURLConnection만으로는 NSURLConnection을 만들 수 없습니다 자체 서명 된 서버를 자동으로 인증하십시오. 여전히 아래 코드를 NSURLConnection 델리게이트 에 추가해야하며, Apple 샘플 코드 AdvancedURLConnections 에서 복사되었으며, 애플 샘플 코드에서 두 개의 파일 (Credentials.h, Credentials.m)을 프로젝트에 추가해야합니다.
- (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 기능 의 기본 동작입니다 .
사전 에서 Info.plist
로 설정 NSAllowsArbitraryLoads
하여 에서이 동작을 재정의 할 수 있습니다 . 그러나 테스트 목적으로 만이 설정을 재정의하는 것이 좋습니다.YES
NSAppTransportSecurity
자세한 내용은 여기에서 App Transport Technote를 참조 하십시오 .
Nathan de Vries가 게시 한 범주 해결 방법은 AppStore 개인 API 검사를 통과하며 NSUrlConnection
개체를 제어 할 수없는 경우에 유용 합니다. 하나의 예는 NSXMLParser
제공 한 URL을 열지 만 NSURLRequest
또는을 노출 시키지는 않습니다 NSURLConnection
.
iOS 4에서는 해결 방법이 여전히 작동하는 것처럼 보이지만 장치에서만 시뮬레이터가 allowsAnyHTTPSCertificateForHost:
더 이상 메서드를 호출하지 않습니다 .
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];
자체 생성 된 인증서 (및 무료 인증서를 얻는 방법 -Cocoanetics의 주석 하단 참조)에 대해 올바르게 인증 할 수있는 요점 코드 (다른 사람의 작업에 따라 ) 를 게시했습니다.
내 코드는 여기에 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];
당신이 여기 볼 수 있습니다 : 오브젝티브 C SSL 동기 연결
AFNetworking을 사용하면 아래 코드로 https 웹 서비스를 성공적으로 소비했습니다.
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
'Programing' 카테고리의 다른 글
http 헤더 값의 최대 값? (0) | 2020.03.15 |
---|---|
텍스트 파일을 한 줄씩 읽는 가장 빠른 방법은 무엇입니까? (0) | 2020.03.15 |
대소 문자를 구분하지 않는 문자열 대체 방법이 있습니까? (0) | 2020.03.15 |
클래스 패스 란 무엇이며 어떻게 설정합니까? (0) | 2020.03.15 |
Django가있는 AngularJS-템플릿 태그 충돌 (0) | 2020.03.15 |