如何使用 NSURLConnection 与 SSL 连接以获得不受信任的证书?
我有以下简单的代码来连接到 SSL 网页,
NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];
但如果证书是自签名的,它会给出错误Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930“不受信任的服务器证书”。
是有没有办法将其设置为接受连接(就像在浏览器中您可以按接受)或绕过它的方法?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
有一个受支持的 API 可以完成此任务! 将类似的内容添加到您的
NSURLConnection
委托中:请注意,
connection:didReceiveAuthenticationChallenge:
可以在向用户呈现一个对话框后(很长时间)将其消息发送到challenge.sender如果需要的话等等There is a supported API for accomplishing this! Add something like this to your
NSURLConnection
delegate:Note that
connection:didReceiveAuthenticationChallenge:
can send its message to challenge.sender (much) later, after presenting a dialog box to the user if necessary, etc.如果您不愿意(或无法)使用私有 API,可以使用一个开源(BSD 许可证)库,名为 ASIHTTPRequest< /a> 提供了一个围绕较低级别的 CFNetwork API 的包装器。 他们最近引入了通过
-setValidatesSecureCertificate:
API 允许使用自签名或不受信任证书的HTTPS 连接
的功能。 如果您不想引入整个库,您可以使用源代码作为自己实现相同功能的参考。If you're unwilling (or unable) to use private APIs, there's an open source (BSD license) library called ASIHTTPRequest that provides a wrapper around the lower-level
CFNetwork APIs
. They recently introduced the ability to allowHTTPS connections
using self-signed or untrusted certificates with the-setValidatesSecureCertificate:
API. If you don't want to pull in the whole library, you could use the source as a reference for implementing the same functionality yourself.理想情况下,iOS 应用程序只需要在两种情况下接受不受信任的证书。
场景 A:您连接到使用自签名证书的测试环境。
场景 B:您使用 Burp Suite、Fiddler、OWASP ZAP 等 MITM 代理来代理 HTTPS 流量。代理将返回由自签名 CA 签名的证书以便代理能够捕获
HTTPS
流量。生产主机绝不应出于明显原因而使用不受信任的证书。
如果您需要让 iOS 模拟器接受不受信任的证书以进行测试,强烈建议您不要更改应用程序逻辑,以禁用
NSURLConnection
API 提供的内置证书验证。 如果应用程序在没有删除此逻辑的情况下向公众发布,它将容易受到中间人攻击。出于测试目的接受不受信任的证书的推荐方法是将签署该证书的证书颁发机构 (CA) 证书导入到您的 iOS 模拟器或 iOS 设备上。 我写了一篇简短的博客文章,演示了如何在 iOS 模拟器中执行此操作:
使用 ios 模拟器接受不受信任的证书
Ideally, there should only be two scenarios of when an iOS application would need to accept an un-trusted certificate.
Scenario A: You are connected to a test environment which is using a self-signed certificate.
Scenario B: You are Proxying
HTTPS
traffic using aMITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.
The Proxies will return a certificate signed by a self-signed CA so that the proxy is able to captureHTTPS
traffic.Production hosts should never use un-trusted certificates for obvious reasons.
If you need to have the iOS simulator accept an un-trusted certificate for testing purposes it is highly recommended that you do not change application logic in order disable the built in certificate validation provided by the
NSURLConnection
APIs. If the application is released to the public without removing this logic, it will be susceptible to man-in-the-middle attacks.The recommended way to accept un-trusted certificates for testing purposes is to import the Certificate Authority(CA) certificate which signed the certificate onto your iOS Simulator or iOS device. I wrote up a quick blog post which demonstrates how to do this which an iOS Simulator at:
accepting untrusted certificates using the ios simulator
NSURLRequest
有一个名为setAllowsAnyHTTPSCertificate:forHost:
的私有方法,它将完全按照您的意愿执行操作。 您可以通过类别在NSURLRequest
上定义allowsAnyHTTPSCertificateForHost:
方法,并将其设置为为您想要覆盖的主机返回YES
。NSURLRequest
has a private method calledsetAllowsAnyHTTPSCertificate:forHost:
, which will do exactly what you'd like. You could define theallowsAnyHTTPSCertificateForHost:
method onNSURLRequest
via a category, and set it to returnYES
for the host that you'd like to override.为了补充已接受的答案,为了更好的安全性,您可以将服务器证书或您自己的根 CA 证书添加到钥匙串( https:// stackoverflow.com/a/9941559/1432048),但是单独执行此操作不会使 NSURLConnection 自动验证您的自签名服务器。 您仍然需要将以下代码添加到您的 NSURLConnection 委托中,它是从 Apple 示例代码 AdvancedURLConnections,并且您需要将苹果示例代码中的两个文件(Credentials.h、Credentials.m)添加到您的项目中。
To complement the accepted answer, for much better security, you could add your server certificate or your own root CA certificate to keychain( https://stackoverflow.com/a/9941559/1432048), however doing this alone won't make NSURLConnection authenticate your self-signed server automatically. You still need to add the below code to your NSURLConnection delegate, it's copied from Apple sample code AdvancedURLConnections, and you need to add two files(Credentials.h, Credentials.m) from apple sample code to your projects.
我对此没有任何功劳,但是我发现了这个< /a> 非常适合我的需求。
shouldAllowSelfSignedCert
是我的BOOL
变量。 只需添加到您的NSURLConnection
委托中,您就可以在每个连接的基础上快速绕过。I can't take any credit for this, but this one I found worked really well for my needs.
shouldAllowSelfSignedCert
is myBOOL
variable. Just add to yourNSURLConnection
delegate and you should be rockin for a quick bypass on a per connection basis.在 iOS 9 中,对于所有无效或自签名证书,SSL 连接都将失败。 这是新的应用传输安全 iOS 9.0 或更高版本以及 OS X 10.11 和更高版本中的功能。
您可以通过在
NSAppTransportSecurity
字典中将NSAllowsArbitraryLoads
设置为YES
在Info.plist
中覆盖此行为。 但是,我建议仅出于测试目的覆盖此设置。有关信息,请参阅应用程序传输技术说明 此处。
In iOS 9, SSL connections will fail for all invalid or self-signed certificates. This is the default behavior of the new App Transport Security feature in iOS 9.0 or later, and on OS X 10.11 and later.
You can override this behavior in the
Info.plist
, by settingNSAllowsArbitraryLoads
toYES
in theNSAppTransportSecurity
dictionary. However, I recommend overriding this setting for testing purposes only.For information see App Transport Technote here.
Nathan de Vries 发布的类别解决方法将通过 AppStore 私有 API 检查,并且在您无法控制
NSUrlConnection
对象的情况下非常有用。一个示例是
NSXMLParser
,它将打开您提供的 URL,但不会公开NSURLRequest
或NSURLConnection
。在 iOS 4 中,解决方法似乎仍然有效,但仅在设备上,模拟器不再调用
allowsAnyHTTPSCertificateForHost:
方法。The category workaround posted by Nathan de Vries will pass the AppStore private API checks, and is useful in cases where you do not have control of the
NSUrlConnection
object.One example is
NSXMLParser
which will open the URL you supply, but does not expose theNSURLRequest
orNSURLConnection
.In iOS 4 the workaround still seems to work, but only on the device, the Simulator does not invoke the
allowsAnyHTTPSCertificateForHost:
method anymore.您必须使用 NSURLConnectionDelegate 来允许 HTTPS 连接,并且 iOS8 中有新的回调。
已弃用:
相反,您需要声明:
通过
willSendRequestForAuthenticationChallenge
,您可以像使用已弃用的方法一样使用challenge
,例如:You have to use
NSURLConnectionDelegate
to allow HTTPS connections and there are new callbacks with iOS8.Deprecated:
Instead those, you need to declare:
With
willSendRequestForAuthenticationChallenge
you can usechallenge
like you did with the deprecated methods, for example:我发布了一些要点代码(基于我注意到的其他人的工作),可以让您根据自行生成的证书进行正确的身份验证(以及如何获得免费证书 - 请参阅 Cocoanetics)
我的代码在这里 github
I posted some gist code (based on someone else's work which I note) that lets you properly authenticate against a self generated certificate (and how to get a free certificate - see comments bottom of Cocoanetics)
My code is here github
您可以使用此代码
使用
-connection:willSendRequestForAuthenticationChallenge:
而不是这些已弃用的方法已弃用:
You can use this Code
Use
-connection:willSendRequestForAuthenticationChallenge:
instead of these Deprecated MethodsDeprecated:
如果您想继续使用 sendSynchronousRequest 我在这个解决方案中工作:
您可以在这里看到它:Objective-C SSL同步连接
If you want to keep using sendSynchronousRequest i work in this solution:
you can see it here: Objective-C SSL Synchronous Connection
使用 AFNetworking 我已经使用以下代码成功使用了 https webservice,
With AFNetworking I have successfully consumed https webservice with below code,