Objetivo-C/Cacau:Como aceito um certificado de servidor inválido?
-
08-06-2019 - |
Pergunta
Usando Solicitação NSURL, estou tentando acessar um site que possui um certificado expirado.Quando eu envio a solicitação, meu conexão: didFailWithError O método delegado é invocado com as seguintes informações:
-1203, NSURLErrorDomain, bad server certificate
Minhas pesquisas encontraram apenas uma solução:um método de classe oculto em NSURLRequest:
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:myHost];
No entanto, não quero usar APIs privadas em um aplicativo de produção por motivos óbvios.
Alguma sugestão sobre o que fazer?Preciso usar APIs CFNetwork e, em caso afirmativo, duas perguntas:
- Algum código de exemplo que eu possa usar para começar?Não encontrei nenhum online.
- Se eu usar CFNetwork para isso, terei que abandonar totalmente o NSURL?
EDITAR:
O iPhone OS 3.0 introduziu um método compatível para fazer isso.Mais detalhes aqui: Como usar o NSURLConnection para conectar-se ao SSL para um certificado não confiável?
Solução 3
O iPhone OS 3.0 introduziu uma maneira suportada de fazer isso que não requer APIs CFNetwork de nível inferior.Mais detalhes aqui:
Como usar o NSURLConnection para conectar-se ao SSL para um certificado não confiável?
Outras dicas
A maneira suportada de fazer isso requer o uso do CFNetwork.Você precisa anexar um kCFStreamPropertySSLSettings ao fluxo que especifica kCFStreamSSLValidatesCertificateChain == kCFBooleanFalse.Abaixo está um código rápido que faz isso, menos a verificação de resultados válidos e a limpeza.Depois de fazer isso, você pode usar CFReadStreamRead() para obter os dados.
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://www.apple.com"), NULL);
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), myURL, kCFHTTPVersion1_1);
CFReadStreamRef myStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
CFMutableDictionaryRef myDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDict, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
CFReadStreamSetProperty(myStream, kCFStreamPropertySSLSettings, myDict);
CFReadStreamOpen(myStream);
Se for para um servidor interno para fins de teste, por que não apenas importar o certificado do servidor de teste para o KeyChain e definir configurações de confiança personalizadas?
Encontrei o mesmo problema - estava desenvolvendo um cliente SOAP e o servidor de desenvolvimento possui um certificado "caseiro".Não consegui resolver o problema mesmo usando esse método, pois não estava usando NSURL, mas sim os métodos WS (mal documentados e aparentemente abandonados), e decidi por enquanto (internamente) apenas usar um não-SSL conexão.
Dito isto, no entanto, a questão que vem à mente é: se você não deseja usar uma API privada em um aplicativo de produção, deveria permitir o acesso a um site com um certificado duvidoso?
vou citar Jens Alfke:
Isso não é apenas um problema teórico de segurança.Algo
cerca de 25% dos servidores DNS públicos foram comprometidos, de acordo com
relatórios recentes e pode direcionar os usuários para sites de phishing/malware/anúncios, mesmo
se eles inserirem o nome de domínio corretamente.A única coisa que protege você
a partir disso está a verificação do certificado SSL.
Você pode criar um certificado autoassinado e adicionar sua autoridade de certificação personalizada às CAs confiáveis?Não tenho certeza de como isso funcionaria no iPhone, mas presumo que no Mac OS X você os adicionaria ao Keychain.
Você também pode estar interessado neste post Ré:Como lidar com erro de certificado incorreto em NSURLDownload
Outra opção seria usar uma biblioteca de conexão alternativa.
Sou um grande fã do AsyncSocket e ele oferece suporte para certificados autoassinados
http://code.google.com/p/cocoaasyncsocket/
Dê uma olhada, acho que é muito mais robusto que o NSURLRequests padrão.