Güvenilmeyen bir sertifika için SSL ile bağlanmak için NSURLConnection nasıl kullanılır?


300

Bir SSL web sayfasına bağlanmak için aşağıdaki basit kod var

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

Sertifika kendinden imzalı olan bir hata ise, Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".yine de bağlantıları kabul edecek şekilde ayarlamanın bir yolu var mı (tıpkı kabul etmek için bir tarayıcıda olduğu gibi) veya baypas etmenin bir yolu var mı?

Yanıtlar:


415

Bunu başarmak için desteklenen bir API var! NSURLConnectionTemsilcinize böyle bir şey ekleyin :

- (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:Gerekirse kullanıcıya bir iletişim kutusu sunduktan sonra mesajını challenge.sender'a (çok) gönderebileceğini unutmayın .


31
Çok teşekkürler, mükemmel çalışıyor. Herhangi bir https sitesini kabul etmek istiyorsanız, iki ifs'i kaldırın ve didReceiveAuthentificationChallenge geri aramasında yalnızca useCendential bölümünü saklayın.
yonel

19
güvenilir olan nedir, nerede n nasıl tanımlanır
Ameya

7
Ameya, bu NSString nesnelerinin bir NSArray'i olurdu. Dizeler @ "google.com" gibi ana bilgisayar adlarıdır.
William Denniss

19
Bu kod iyi çalışıyor. Ancak, geçerli sertifikalara sahip olmanın tümünün, ortadaki adam saldırılarını önlemek olduğunu unutmayın. Bu kodu kullanırsanız, birisi "güvenilir ana bilgisayar" adında sahtekarlık yapabilir. Yine de SSL'nin veri şifreleme özelliklerini alıyorsunuz, ancak ana bilgisayar kimlik doğrulama özelliklerini kaybediyorsunuz.
William Denniss

42
Bu yöntemlerin artık iOS 5.0 ve Mac OS X 10.6'dan itibaren kullanımdan kaldırıldığı düşünülmektedir. Bunun -(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challengeyerine yöntem kullanılmalıdır.
Andrew R.

36

Özel API'leri kullanmak istemiyorsanız (veya kullanamıyorsanız), ASIHTTPRequest adında , alt düzey çevresinde bir sarmalayıcı sağlayan açık kaynaklı (BSD lisansı) bir kitaplık vardır CFNetwork APIs. Son zamanlarda HTTPS connections, -setValidatesSecureCertificate:API ile kendinden imzalı veya güvenilmeyen sertifikaların kullanılmasına izin verme yeteneğini tanıttılar . Kütüphanenin tamamını çekmek istemiyorsanız, kaynağı aynı işlevselliği kendiniz uygulamak için referans olarak kullanabilirsiniz.


2
Tim, kendinizi başka nedenlerle async kullanmak istediğinizde bulabilirsiniz (ilerleme çubuğunu gösterme gibi), en basit istekler dışında bu şekilde gidiyorum. Belki de Async'i şimdi uygulamanız ve güçlüğü daha sonra kaydetmelisiniz.
William Denniss

Uygulama için buna bakın (ancak [r setValidatesSecureCertificate: NO];) kullanın: stackoverflow.com/questions/7657786/…
Sam Brodkin

Bu konuyu tekrar gündeme getirdiğim için üzgünüm. Ancak iOS 5, ARC özelliklerini tanıttığından beri. Bu işi şimdi nasıl yapabilirim?
Melvin Lai

Lütfen bunu kontrol edebilir misiniz: stackoverflow.com/q/56627757/1364053
nr5

33

İdeal olarak, bir iOS uygulamasının güvenilir olmayan bir sertifikayı ne zaman kabul etmesi gerektiğine dair yalnızca iki senaryo olmalıdır.

Senaryo A: Kendinden imzalı bir sertifika kullanan bir test ortamına bağlısınız.

Senaryo B: Bir proxy HTTPSkullanarak trafiğe MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.proxy veriyorsunuz Proxy'ler, proxy'nin HTTPStrafiği yakalayabilmesi için kendinden imzalı bir CA tarafından imzalanan bir sertifika döndürür .

Üretim ana makineleri, açık nedenlerle asla güvenilir olmayan sertifikalar kullanmamalıdır .

İOS simülatörünün test amacıyla güvenilir olmayan bir sertifikayı kabul etmesi gerekiyorsa, cihaz tarafından sağlanan yerleşik sertifika doğrulamasını devre dışı bırakmak için uygulama mantığını değiştirmemeniz şiddetle önerilir. NSURLConnection API'lar . Uygulama bu mantık kaldırılmadan halka açıklanırsa, ortadaki adam saldırılarına açık olacaktır.

Test amacıyla güvenilir olmayan sertifikaları kabul etmenin önerilen yolu, sertifikayı imzalayan Sertifika Yetkilisi (CA) sertifikasını iOS Simulator veya iOS cihazınıza aktarmaktır. Bir iOS Simulator'ın bunu nasıl yapacağını gösteren hızlı bir blog yazısı yazdım:

ios simülatörünü kullanarak güvenilmeyen sertifikaları kabul etme


1
Harika şeyler dostum. Kabul ediyorum, güvenilir olmayan herhangi bir sertifikayı kabul etmek için bu özel uygulama mantığını devre dışı bırakmayı unutmak çok kolay.
Tomasz

"İdeal olarak, bir iOS uygulamasının güvenilir olmayan bir sertifikayı ne zaman kabul etmesi gerektiğine dair yalnızca iki senaryo olmalıdır." - Bir sertifikayı sabitlerken 'iddia edilen' bir sertifikayı reddetmeye ne dersiniz? Confer: Dignotar (pwn'd) ve Trustwave (MitM şöhreti).
jww

Kodu kaldırmayı unutma konusundaki ifadenizi tamamen kabul edin. İroni, kodda bu değişikliği yapmanın, simülatörün kendinden imzalı sertifikaları kabul etmesini sağlamaktan çok daha kolay olmasıdır.
devios1

12

NSURLRequest, setAllowsAnyHTTPSCertificate:forHost:tam olarak istediğinizi yapacak özel bir yönteme sahiptir . allowsAnyHTTPSCertificateForHost:Yöntemi NSURLRequestbir kategori üzerinden tanımlayabilir ve YESgeçersiz kılmak istediğiniz ana makine için geri dönecek şekilde ayarlayabilirsiniz .


Belgelenmemiş API'lerle ilgili olağan uyarılar geçerlidir ... ancak bunun mümkün olduğunu bilmek güzel.
Stephen Darlington

Evet kesinlikle. Özel API'ların kullanımını içermeyen başka bir yanıt ekledim.
Nathan de Vries

"NSURLConnection sendSynchronousRequest:" kullandığınızda işe yarar mı?
Tim Büthe

11

Kabul edilen yanıtı tamamlamak için, çok daha iyi bir güvenlik için, sunucu sertifikanızı veya kendi kök CA sertifikanızı anahtarlığa ekleyebilirsiniz ( https://stackoverflow.com/a/9941559/1432048 ), ancak bunu tek başına yapmak NSURLConnection yapmaz otomatik olarak imzalanan sunucunuzun kimliğini otomatik olarak doğrulayın. Yine de aşağıdaki kodu NSURLConnection temsilcinize eklemeniz gerekir, Apple örnek kodu AdvancedURLConnections'dan kopyalanır ve apple örnek kodundan projelerinize iki dosya (Credentials.h, Credentials.m) eklemeniz gerekir.

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

10

Bunun için herhangi bir kredi alamıyorum, ama buldum bu benim ihtiyaçları için gerçekten iyi çalıştı. shouldAllowSelfSignedCertbenim BOOLdeğişkenim. NSURLConnectionTemsilcinize eklemeniz yeterlidir ve her bağlantı için hızlı bir baypas yapmanız gerekir.

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

İOS 9'da, tüm geçersiz veya kendinden imzalı sertifikalar için SSL bağlantıları başarısız olur. Bu, iOS 9.0 veya sonraki sürümlerde ve OS X 10.11 ve sonraki sürümlerde yeni App Transport Security özelliğinin varsayılan davranışıdır .

Sen bu davranışı geçersiz kılabilirsiniz Info.plistayarlayarak, NSAllowsArbitraryLoadshiç YESde NSAppTransportSecuritysözlüğe. Ancak, bu ayarı yalnızca test amacıyla geçersiz kılmanızı öneririm.

resim açıklamasını buraya girin

Bilgi için buradaki Uygulama Aktarım Tekniğine bakın .


Benim için çalışan tek çözüm, Firebase çerçevesini ihtiyaçlarımı karşılayacak şekilde değiştiremem, çözdü, teşekkürler!
Yitzchak

Şimdi Google'ın NSAllowArbitraryLoads = Admob için EVET (Firebase'de) istediğini gördüm. firebase.google.com/docs/admob/ios/ios9
Yitzchak

6

Nathan de Vries tarafından yayınlanan kategori geçici çözümü AppStore özel API denetimlerini geçecek ve NSUrlConnectionnesnenin denetiminin olmadığı durumlarda yararlı olacaktır . Bir örnek, NSXMLParsersağladığınız URL'yi açacak, ancak NSURLRequestveya öğesini göstermeyecektir NSURLConnection.

İOS 4'te geçici çözüm hala çalışıyor gibi görünüyor, ancak sadece cihazda Simulator allowsAnyHTTPSCertificateForHost:artık yöntemi çağırmıyor.


6

NSURLConnectionDelegateHTTPS bağlantılarına izin vermek için kullanmanız gerekir ve iOS8 ile yeni geri aramalar vardır.

Kullanımdan kaldırılan:

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

Bunun yerine, beyan etmelisiniz:

connectionShouldUseCredentialStorage: - URL yükleyicinin bağlantıyı doğrulamak için kimlik bilgileri deposunu kullanıp kullanmayacağını belirlemek için gönderilir.

connection:willSendRequestForAuthenticationChallenge: - Temsilciye bağlantının bir kimlik doğrulama sorgusu için istek göndereceğini söyler.

İle willSendRequestForAuthenticationChallengekullanabileceğiniz challengeörneğin kullanımdan kaldırılmış yöntemleri ile yaptığı gibi:

// Trusting and not trusting connection to host: Self-signed certificate
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];

Lütfen bunu kontrol edebilir misiniz: stackoverflow.com/q/56627757/1364053
nr5

3

Kendi ürettiğimiz bir sertifikaya karşı doğru bir şekilde kimlik doğrulaması yapmanıza izin veren (ve bir başka kişinin çalışmasına bağlı olarak) bazı gist kodları yayınladım (ve ücretsiz bir sertifika nasıl edinebilirsiniz - Cocoanetics'in altındaki yorumlara bakın )

Kodum burada github


Lütfen bunu kontrol edebilir misiniz: stackoverflow.com/q/56627757/1364053
nr5

2

SendSynchronousRequest kullanmaya devam etmek istiyorsanız bu çözümde çalışıyorum:

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

burada görebilirsiniz: Objective-C SSL Senkron Bağlantı


1

AFNetworking ile https web servisini aşağıdaki kodla başarıyla kullandım,

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

Bu Kodu kullanabilirsiniz

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

kullanım -connection:willSendRequestForAuthenticationChallenge:Bu Kullanımdan Kaldırılmış Yöntemler yerine

Kullanımdan kaldırılan:

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace  
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
-(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.