How Can I Access Local Https with invalid certificate With Alamofire?

末鹿安然 提交于 2020-12-06 16:04:04

问题


I'm trying to connect to a Webserver on a local network using Alamofire. If I open the url with a browser, it gives a ssl warning. If I just ignore and add the exception to the browser, it definitely works.
I read different posts on this topic including Alamofire Github page, but I wasn't able to get it to work. What am I doing wrong?
Thanks in advance!
Here is the testing code:
I declared the manager in the beginning of the code right below class ViewController.

let manager = SessionManager(configuration: URLSessionConfiguration.default, serverTrustPolicyManager: ServerTrustPolicyManager(policies:["10.0.1.19:4491":.disableEvaluation]))
let parameters:Parameters = ["macro":"696B38D0-AF57-4991-83DD-DFD03F1A693B", "value":""]
manager.request("https://10.0.1.19:4491/authenticatedaction.html", parameters:parameters).authenticate(user:user, password:password).response {
 response in
  debugPrint(response)
}

Here is the error:

Alamofire.DefaultDataResponse(request: Optional(https://10.0.1.19:4491/authenticatedaction.html?macro=696B38D0-AF57-4991-83DD-DFD03F1A693B&value=), response: nil, data: Optional(0 bytes), error: Optional(Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “10.0.1.19†which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x170134a00>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813, NSErrorPeerCertificateChainKey=(
    "<cert(0x108066e00) s: Keyboard Maestro i: Keyboard Maestro CA>"
), NSUnderlyingError=0x170259d70 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x170134a00>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813, kCFStreamPropertySSLPeerCertificates=(
    "<cert(0x108066e00) s: Keyboard Maestro i: Keyboard Maestro CA>"
)}}, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “10.0.1.19†which could put your confidential information at risk., NSErrorFailingURLKey=https://10.0.1.19:4491/authenticatedaction.html?macro=696B38D0-AF57-4991-83DD-DFD03F1A693B&value=, NSErrorFailingURLStringKey=https://10.0.1.19:4491/authenticatedaction.html?macro=696B38D0-AF57-4991-83DD-DFD03F1A693B&value=, NSErrorClientCertificateStateKey=0}), timeline: Timeline: { "Request Start Time": 517316327.668, "Initial Response Time": 517316327.911, "Request Completed Time": 517316327.911, "Serialization Completed Time": 517316327.912, "Latency": 0.243 secs, "Request Duration": 0.243 secs, "Serialization Duration": 0.001 secs, "Total Duration": 0.244 secs }, _metrics: Optional((Task Interval) <_NSConcreteDateInterval: 0x17002b6e0> (Start Date) 2017-05-24 10:58:47 +0000 + (Duration) 0.251558 seconds = (End Date) 2017-05-24 10:58:47 +0000
(Redirect Count) 0
(Transaction Metrics) (Request) <NSURLRequest: 0x170013cd0> { URL: https://10.0.1.19:4491/authenticatedaction.html?macro=696B38D0-AF57-4991-83DD-DFD03F1A693B&value= }
(Response) (null)
(Fetch Start) 2017-05-24 10:58:47 +0000
(Domain Lookup Start) (null)
(Domain Lookup End) (null)
(Connect Start) (null)
(Secure Connection Start) (null)
(Secure Connection End) (null)
(Connect End) (null)
(Request Start) 2017-05-24 10:58:47 +0000
(Request End) 2017-05-24 10:58:47 +0000
(Response Start) 2017-05-24 10:58:47 +0000
(Response End) (null)
(Protocol Name) (null)
(Proxy Connection) NO
(Reused Connection) YES
(Fetch Type) Unknown
))

回答1:


I finally sorted out my problems. There were two problems.
1. I needed to declare sessionManager outside the function.
let manager = SessionManager(configuration: URLSessionConfiguration.default, serverTrustPolicyManager: ServerTrustPolicyManager(policies:["localhost":.disableEvaluation]))
2. I read somewhere that you need to include port number for the host, but that actually caused the problem for me.
It seems like you just need to write "localhost" Instead of "localhost:443".
Regardless, here is the entire code that will disable evaluation for all addresses.
You don't need to change anything to Info.plist. The default Info.plist that Xcode gives you seem to work.
IOS 10.3.2, Xcode 8.3.2, Alamofire Master branch from Github (2017-05-23)

import UIKit
import Alamofire

class ViewController: UIViewController {

    open class MyServerTrustPolicyManager: ServerTrustPolicyManager {
        open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
            return ServerTrustPolicy.disableEvaluation
        }
    }

    let sessionManager = SessionManager(delegate:SessionDelegate(), serverTrustPolicyManager:MyServerTrustPolicyManager(policies: [:]))

    func connect() {
        let user = "user"
        let password = "password"
        let parameters:Parameters = ["parameter1":"value1", "parameter2":"value2"]
        sessionManager.request("https://localhost:443/index.php", parameters:parameters).authenticate(user:user, password:password).responseString {
            response in
                debugPrint(response.result.value)
            } else {
                debugPrint(response)
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        connect()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}



回答2:


It's stated on Alamofire documentation on github when using SessionManager:

Make sure to keep a reference to the new SessionManager instance, otherwise your requests will all get cancelled when your sessionManager is deallocated.

For start you can make it as global variable.

Example:

let sessionManager: SessionManager = {
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "10.0.1.19": .disableEvaluation
    ]

    return SessionManager(
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )
}()

When working with self-signed or invalid certificates in development environment NSAppTransportSecurity may be added and NSAllowsArbitraryLoads set to </true> in Info.plist. Note that it's not recommended for production environments.

Detailed explanation can be found in Alamofire documentation:

App Transport Security

With the addition of App Transport Security (ATS) in iOS 9, it is possible that using a custom ServerTrustPolicyManager with several ServerTrustPolicy objects will have no effect. If you continuously see CFNetwork SSLHandshake failed (-9806) errors, you have probably run into this problem. Apple's ATS system overrides the entire challenge system unless you configure the ATS settings in your app's plist to disable enough of it to allow your app to evaluate the server trust.

If you run into this problem (high probability with self-signed certificates), you can work around this issue by adding the following to your Info.plist.

<dict>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>example.com</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSIncludesSubdomains</key>
                <true/>
                <!-- Optional: Specify minimum TLS version -->
                <key>NSTemporaryExceptionMinimumTLSVersion</key>
                <string>TLSv1.2</string>
            </dict>
        </dict>
    </dict>
</dict>

Whether you need to set the NSExceptionRequiresForwardSecrecy to NO depends on whether your TLS connection is using an allowed cipher suite. In certain cases, it will need to be set to NO. The NSExceptionAllowsInsecureHTTPLoads MUST be set to YES in order to allow the SessionDelegate to receive challenge callbacks. Once the challenge callbacks are being called, the ServerTrustPolicyManager will take over the server trust evaluation. You may also need to specify the NSTemporaryExceptionMinimumTLSVersion if you're trying to connect to a host that only supports TLS versions less than 1.2.

It is recommended to always use valid certificates in production environments.



来源:https://stackoverflow.com/questions/44146797/how-can-i-access-local-https-with-invalid-certificate-with-alamofire

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!