此代码尝试访问并且无法访问在浏览器中运行的SSL URL:
let path = "https://localhost:8443/greeting"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
if let c = json["content"].string {
print(c)
}
})
task.resume()
因错误而失败:
可选(错误域= NSURLErrorDomain代码= -1200" SSL错误有 发生并且无法与服务器建立安全连接。" 的UserInfo = {NSURLErrorFailingURLPeerTrustErrorKey =,
允许应用程序接受此证书需要什么?
有问题的证书是自签名的。在SO上阅读一些解决方案但没有成功。
运行Xcode 7.2
答案 0 :(得分:13)
@Ashish Kakkad是当场的。这有效:
class Blah: NSURLSessionDelegate {
func rest() {
let path = "https://localhost:8443/greeting"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
if let c = json["content"].string {
print(c)
}
})
task.resume()
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}
在Info.plist文件中使用它:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
答案 1 :(得分:8)
Sai Reddy的解决方案允许您接受具有完整链的自签名证书,但也可以接受其他人。
Marcus Leon的解决方案是完全替代方案-基本上忽略了所有证书。
我更喜欢这个。
Swift 4.1,iOS 11.4.1
首先,在您的Info.plist中:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
第二,无论您在哪里使用NSURLSession,都无需使用URLSession.shared进行设置,而应使用类似以下的方法:
session = URLSession(configuration: .default, delegate: APIURLSessionTaskDelegate(isSSLPinningEnabled: isSSLPinningEnabled), delegateQueue: nil)
然后添加此类以处理固定:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print("*** received SESSION challenge...\(challenge)")
let trust = challenge.protectionSpace.serverTrust!
let credential = URLCredential(trust: trust)
guard isSSLPinningEnabled else {
print("*** SSL Pinning Disabled -- Using default handling.")
completionHandler(.useCredential, credential)
return
}
let myCertName = "my_certificate_to_pin"
var remoteCertMatchesPinnedCert = false
if let myCertPath = Bundle.main.path(forResource: myCertName, ofType: "der") {
if let pinnedCertData = NSData(contentsOfFile: myCertPath) {
// Compare certificate data
let remoteCertData: NSData = SecCertificateCopyData(SecTrustGetCertificateAtIndex(trust, 0)!)
if remoteCertData.isEqual(to: pinnedCertData as Data) {
print("*** CERTIFICATE DATA MATCHES")
remoteCertMatchesPinnedCert = true
}
else {
print("*** MISMATCH IN CERT DATA.... :(")
}
} else {
print("*** Couldn't read pinning certificate data")
}
} else {
print("*** Couldn't load pinning certificate!")
}
if remoteCertMatchesPinnedCert {
print("*** TRUSTING CERTIFICATE")
completionHandler(.useCredential, credential)
} else {
print("NOT TRUSTING CERTIFICATE")
completionHandler(.rejectProtectionSpace, nil)
}
}
}
此类检查您是否启用了证书固定。如果您这样做,它将完全忽略常规证书验证,并与我们包含在应用程序中的证书进行精确比较。这样,它仅接受您的自签名证书,而不接受其他任何内容。
此解决方案要求您在项目的“资源”文件夹中放置一个“ my_certificate_to_pin.der ”文件。如果您还没有“资源”文件夹,只需添加一个。
该证书应为DER格式。
要为服务器创建自签名证书,通常需要执行以下操作:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mycert.key -out mycert.cer
这将生成两个文件-一个 mycert.key 私钥文件和一个 mycert.cer -证书本身。它们都是X509格式。对于iOS,您将需要DER格式的证书,因此请执行以下操作:
openssl x509 -outform der -in mycert.cer -out my_certificate_to_pin.der
这会生成您在iOS上所需的文件。
答案 2 :(得分:2)
您可以使用自己的证书而不是我的证书(fullchain.pem)
class AccessingServer: NSObject,URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
// First load our extra root-CAs to be trusted from the app bundle.
let trust = challenge.protectionSpace.serverTrust
let rootCa = "fullchain"
if let rootCaPath = Bundle.main.path(forResource: rootCa, ofType: "pem") {
if let rootCaData = NSData(contentsOfFile: rootCaPath) {
let rootCert = SecCertificateCreateWithData(nil, rootCaData)
// let certArrayRef = CFArrayCreate(nil, UnsafeMutablePointer<UnsafePointer<Any>>([rootCert]), 1, nil)
SecTrustSetAnchorCertificates(trust!, rootCert as! CFArray)
SecTrustSetAnchorCertificatesOnly(trust!, false)
}
}
var trustResult: SecTrustResultType = SecTrustResultType.invalid
SecTrustEvaluate(trust!, &trustResult)
if (trustResult == SecTrustResultType.unspecified ||
trustResult == SecTrustResultType.proceed) {
// Trust certificate.
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
challenge.sender?.use(credential, for: challenge)
} else {
NSLog("Invalid server certificate.")
challenge.sender?.cancel(challenge)
}
} else {
NSLog("Got unexpected authentication method \(challenge.protectionSpace.authenticationMethod)");
challenge.sender?.cancel(challenge)
}
}
}