问题
I am creating an iPad app that accesses HTTPS web services. I want to implement pinning, but am having issues.
This class creates the Alamofire Manager (mostly taken from documentation):
class NetworkManager {
var manager: Manager?
init() {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"www.google.co.uk": .PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .DisableEvaluation
]
manager = Alamofire.Manager(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}
}
This function makes the call:
static let networkManager = NetworkManager()
public static func testPinning() {
networkManager.manager!.request(.GET, "https://www.google.co.uk").response { response in
if response.1 != nil {
print("Success")
print(response.1)
print(response.1?.statusCode)
} else {
print("Error")
print(response.3)
}
}
}
The certificate is saved in the project and shows under 'Targets > Build Phases > Copy Bundle Resources'.
I am currently receiving the following error every time I make the request (from the else block in testPinning()
):
Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://www.google.co.uk/, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://www.google.co.uk/})
回答1:
So, the issue was that the certificate was saved in the wrong format.
ServerTrustPolicy.certificatesInBundle()
finds all certificates in the bundle based on a list of extensions, then tries to load them using SecCertificateCreateWithData
. Per its documentation, this function:
Returns NULL if the data passed in the data parameter is not a valid DER-encoded X.509 certificate
When you export a certificate in Firefox, you have a "format" pop-up at the bottom of the file browser. Select "X.509 Certificate (DER)", and you should get a certificate in the right format for this purpose.
回答2:
First, you need to download the certificate. The best way is to download the certificate on the Firefox browser.
Step 1
Go to your webpage/ API and click the lock icon to get a certificate.
Step 2
Click View Certificate
Step 3
Click Certificate Fields tab's first section and click export
Step 4
Select the Format:- DER
Step 5
Drag and drop the file into your XCode Project
Step 6
Add Certificate under 'Targets > Build Phases > Copy Bundle Resources'
Step 7
Add Network Manager File. Replace your URL with google.com
import Foundation
import Alamofire
import SwiftyJSON
class MYPNetworkManager {
var Manager: SessionManager?
init() {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"https://google.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .disableEvaluation
]
Manager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies:
serverTrustPolicies)
)
}
}
Step 8
Add a file to get the session manager
import Foundation
import Alamofire
import SwiftyJSON
class APIPinning {
private static let NetworkManager = MYPNetworkManager()
public static func getManager() -> SessionManager {
return NetworkManager.Manager!
}
}
Step 9
Use this session manager on Alamofire eg:-
public static func testPinning() {
NetworkManager.Manager!.request("YourURL", method: .get, encoding: URLEncoding.httpBody, headers: MConnect.headersWithToken)
.validate()
.responseJSON { response in
print(response)
switch response.result {
case .success:
if let value = response.result.value {
let json = JSON(value)
print(json)
} else {
}
case .failure:
print("Error")
}
}
}
来源:https://stackoverflow.com/questions/34611112/certificate-pinning-in-alamofire