ssl pinning in Swift AlamoFire - swift

Im a newb here but I have an app that is subject to MITM attacks.
After I bit of research it sounds like I need to do SSL Pining, i.e keep a copy of my servers public key/certificate so the can determine if the response came from it.
I have no idea how to do this, I am using AlamoFire in Swift to handle the networking.

Alamofire now implemented the certificate pinning.
The documentation you need is in the Readme.md
https://github.com/Alamofire/Alamofire
See their example implementation:
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .DisableEvaluation
]
let manager = Manager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)

Alamofire 5.0 is now released. And ssl pinnig is changed. Look at the below code snipped.
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = timeoutIntervalForRequest
let trustManager = ServerTrustManager(evaluators: [
"prod.ehliyetcepte.com": PublicKeysTrustEvaluator(),
"dev.ehliyetcepte.com": DisabledEvaluator()])
self.session = Session(startRequestsImmediately: true,
configuration: configuration,
delegate: self,
serverTrustManager: trustManager)

As indicated here : https://github.com/Alamofire/Alamofire/issues/366
It is certainly something that the community is looking to support, but there's not a solid time frame around it yet. I'd say for the time being, you'll want to continue with AFNetworking, and keep a close eye on the Alamofire project for new features coming in.

Related

Why is ssl pinning not working on synchronous requests?

I want to do ssl pinning with Alamofire library, but it doesn't work for sync requests.
I am using the following library to sync Alamofire request:
https://github.com/Dalodd/Alamofire-Synchronous
In async call I get cancaled with code -999 but when I try with sync I get all responses with 200.
My code is like this:
let hostname = "..."
let cert = "..." // e.g. for cert.der, this should just be "cert"
let pathToCert = Bundle.main.path(forResource: cert, ofType: "der")
let localCertificate = NSData(contentsOfFile: pathToCert!)
let certificates = [SecCertificateCreateWithData(nil,
localCertificate!)!]
// Configure the trust policy manager
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: certificates,
validateCertificateChain: true,
validateHost: true
)
let serverTrustPolicies = [hostname: serverTrustPolicy]
let serverTrustPolicyManager = ServerTrustPolicyManager(policies:
serverTrustPolicies)
// Configure session manager with trust policy
let defaultManager = Alamofire.SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: serverTrustPolicyManager
)
let manager = defaultManager
manager.session.configuration.timeoutIntervalForRequest = 120
let request = getRequest(object, endPoint: endPoint)
let response = manager.request(request).responseString()
If I don't use semaphore in the code below the request is aborted but if I use it I get 200 responses
public func response<T: DataResponseSerializerProtocol>(responseSerializer: T) ->
DataResponse<T.SerializedObject> {
let semaphore = DispatchSemaphore(value: 0)
var result: DataResponse<T.SerializedObject>!
self.response(queue: DispatchQueue.global(qos: .default), responseSerializer: responseSerializer) { response in
result = response
semaphore.signal()
}
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
return result
}
How is this possible?
Using Alamofire synchronously is not supported so any misbehaviors you see when doing this are unlikely to be fixed.
Additionally, that dependency is using Alamofire 4, where 5 is the latest version, so if you really want the behavior I suggest implementing it manually using the latest version.

Swift Switching from HTTPS to HTTP

This one's a weird one.
I have a little API server that does some stuff that I want my mobile app to talk to. It has DNS and SSL correct configured, I can reach it from my browser or postman no problem. Additionally I have set up a 301 redirect to HTTPS if anyone tries to approach it via HTTP.
I have a viewModel in swift thats calling out to this API with a pretty standard set up.
func getEndpointData() {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "mycoolApi.com"
urlComponents.path = "/v1/endpoint/\(model.endpoint.param)"
let url = urlComponents.url!
let session = URLSession(configuration: .default)
session.dataTaskPublisher(for: url)
.tryMap(){ element -> Data in
guard let httpResponse = element.response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return element.data
}
.decode(type: EndpointData.self, decoder: JSONDecoder())
.receive(on: RunLoop.main)
.sink(receiveCompletion: { print("recieved completion \($0)")},
receiveValue: { endpointData in
self.rawData = endpointData.myCoolProperty
})
.store(in: &cancellables)
}
Should be calling via HTTPS right?
Wrong.
This is the error I get:
recieved completion failure(Foundation.URLError(_nsError: Error Domain=NSURLErrorDomain
Code=-1022 "The resource could not be loaded because the App Transport Security policy
requires the use of a secure connection." UserInfo={NSLocalizedDescription=The resource could
not be loaded because the App Transport Security policy requires the use of a secure
connection., NSErrorFailingURLStringKey=http://mycoolApi.com/v1/endpoint/<Path_Param_ID>/,
NSErrorFailingURLKey=http://mycoolApi.com/v1/endpoint/<Path_Param_ID>/,
_NSURLErrorRelatedURLSessionTaskErrorKey=(
I feel like Im taking crazy pills.. Why is the simulator forcing something thats explicitly https to http?
I am not sure if this is the right way but I recently faced this issue on my live app there are two possible solution one you add "App Transport Security Settings" & "Allow Arbitrary Loads" in your info.plist
check out the image for info.plist
Second thing which worked for me https://www.mycoolApi.com so you need "www" after https://

Integrate Apollo subscriptions on iOS with Action Cable being used on the backend for websockets

I'm trying to make Apollo subscriptions on iOS work with a backend that is using Action Cable to implement websockets. I learned that the iOS app needs to send command, channel and channel id to the backend to make subscriptions work (see here). I have tried to use the function write func write(_ str: String, force forced: Bool = false, id: Int? = nil) in WebSocketTransport.swift on WebSocketTransport object when initializing instance of Apollo. Below you can see how I'm doing that.
let userDefault = UserDefaults.standard
var authPayloads = Dictionary<String, String> ()
var authToken = ""
if let token = userDefault.object(forKey: "token") {
authToken = "\(token)"
authPayloads.updateValue(authToken, forKey: "authorization")
}
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = authPayloads
let map: GraphQLMap = authPayloads
let wsEndpointURL = URL(string: "ws://localhost:8080/subscriptions/\(authToken)")!
let endpointURL = URL(string: "http://localhost:8080/api")!
websocket = WebSocketTransport(request: URLRequest(url: wsEndpointURL), connectingPayload: map)
var channelId = Int(arc4random_uniform(100000))
websocket?.write(stringify(json: ["command":"subscribe", "identifier": stringify(json: ["channel":"channelName", "channelId": channelId])]))
let splitNetworkTransport = SplitNetworkTransport(
httpNetworkTransport: HTTPNetworkTransport(
url: endpointURL,
configuration: configuration
),
webSocketNetworkTransport: websocket!
)
return ApolloClient(networkTransport: splitNetworkTransport)
}()
However, the backend isn't seeing what I'm writing to the WebSocket Transport object in their logs and I'm not able to subscribe to that specific channel. Any idea how I can make use Apollo subscriptions on iOS if the backend is using Action Cable, and make the two work together?
The only solution for now is to use Swift-ActionCableClient to recieve streams, and use the mutations/queries from ApolloClient.
Unfortenatly! Apollo iOS doesn't know how to communicate with ActionCable channels, this issue is reported on Apollo-iOS Github Issue #634 & Your issue Github Issue #454

add public key pinning in alamofire manger class swift

here is my alamofire manager, how I can add public key pinning on it ? please help me, I couldn't know the way to do it in my code, if possible I need explanation step by step on how do that with AFManager that has all the requests
class AFManager : NSObject{
///without headers (post)
//used this to registration
class func requestPOSTURL(_ strURL : String, params : [String :
AnyObject]?, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void){
URLCache.shared.removeAllCachedResponses()
Alamofire.request(strURL, method: .post, parameters: params, encoding: URLEncoding.httpBody).responseJSON { (responseObject) -> Void in
//print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error : Error = responseObject.result.error!
failure(error)
}
}
}
///// response string (post)
//used this in login // used in change password
class func strRequestPOSTURL(_ strURL : String, params : [String : String]?, headers : [String : String]?, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void){
URLCache.shared.removeAllCachedResponses()
Alamofire.request(strURL, method: .post, parameters: params, encoding: URLEncoding.httpBody, headers: headers).responseJSON { (response) in
//print(response)
if response.result.isSuccess {
let resJson = JSON(response.result.value!)
success(resJson)
}
if response.result.isFailure {
let error : Error = response.result.error!
failure(error)
}
}
}
}
I saw this sample but didn't know how to do it and where I should put the code see the link below :
https://infinum.co/the-capsized-eight/ssl-pinning-revisited
Security
Using a secure HTTPS connection when communicating with servers and web services is an important step in securing sensitive data. By default, Alamofire will evaluate the certificate chain provided by the server using Apple's built in validation provided by the Security framework. While this guarantees the certificate chain is valid, it does not prevent man-in-the-middle (MITM) attacks or other potential vulnerabilities. In order to mitigate MITM attacks, applications dealing with sensitive customer data or financial information should use certificate or public key pinning provided by the ServerTrustPolicy.
ServerTrustPolicy
The ServerTrustPolicy enumeration evaluates the server trust generally provided by an URLAuthenticationChallenge when connecting to a server over a secure HTTPS connection.
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
)
There are many different cases of server trust evaluation giving you complete control over the validation process:
performDefaultEvaluation: Uses the default server trust evaluation
while allowing you to control whether to validate the host provided
by the challenge.
pinCertificates: Uses the pinned certificates to validate the server
trust. The server trust is considered valid if one of the pinned
certificates match one of the server certificates.
pinPublicKeys: Uses the pinned public keys to validate the server
trust. The server trust is considered valid if one of the pinned
public keys match one of the server certificate public keys.
disableEvaluation: Disables all evaluation which in turn will always
consider any server trust as valid.
customEvaluation: Uses the associated closure to evaluate the
validity of the server trust thus giving you complete control over
the validation process. Use with caution.
Server Trust Policy Manager
The ServerTrustPolicyManager is responsible for storing an internal mapping of server trust policies to a particular host. This allows Alamofire to evaluate each host against a different server trust policy.
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .disableEvaluation
]
let sessionManager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
Make sure to keep a reference to the new SessionManager instance, otherwise your requests will all get cancelled when your sessionManager is deallocated.
These server trust policies will result in the following behavior:
test.example.com will always use certificate pinning with certificate chain and host validation enabled thus requiring the following criteria to be met to allow the TLS handshake to succeed:
Certificate chain MUST be valid.
Certificate chain MUST include one of the pinned certificates.
Challenge host MUST match the host in the certificate chain's leaf certificate.
insecure.expired-apis.com will never evaluate the certificate chain and will always allow the TLS handshake to succeed.
All other hosts will use the default evaluation provided by Apple.
Subclassing Server Trust Policy Manager
If you find yourself needing more flexible server trust policy matching behavior (i.e. wildcarded domains), then subclass the ServerTrustPolicyManager and override the serverTrustPolicyForHost method with your own custom implementation.
class CustomServerTrustPolicyManager: ServerTrustPolicyManager {
override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
var policy: ServerTrustPolicy?
// Implement your custom domain matching behavior...
return policy
}
}
Validating the Host
The .performDefaultEvaluation, .pinCertificates and .pinPublicKeys server trust policies all take a validateHost parameter. Setting the value to true will cause the server trust evaluation to verify that hostname in the certificate matches the hostname of the challenge. If they do not match, evaluation will fail. A validateHost value of false will still evaluate the full certificate chain, but will not validate the hostname of the leaf certificate.
It is recommended that validateHost always be set to true in production environments.
Validating the Certificate Chain
Pinning certificates and public keys both have the option of validating the certificate chain using the validateCertificateChain parameter. By setting this value to true, the full certificate chain will be evaluated in addition to performing a byte equality check against the pinned certificates or public keys. A value of false will skip the certificate chain validation, but will still perform the byte equality check.
There are several cases where it may make sense to disable certificate chain validation. The most common use cases for disabling validation are self-signed and expired certificates. The evaluation would always fail in both of these cases, but the byte equality check will still ensure you are receiving the certificate you expect from the server.
It is recommended that validateCertificateChain always be set to true in production environments.
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.
Using Self-Signed Certificates with Local Networking
If you are attempting to connect to a server running on your localhost, and you are using self-signed certificates, you will need to add the following to your Info.plist.
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
</dict>
According to Apple documentation, setting NSAllowsLocalNetworking to YES allows loading of local resources without disabling ATS for the rest of your app.
Reference:-
https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md
For implementation details refer the tests.
https://github.com/Alamofire/Alamofire/blob/master/Tests/TLSEvaluationTests.swift#L290-L450
SSL pinning using TrustKit with Alamofire. Here I have included API Manager class. This will help you solve using Alamofire with TrustKit.
class ApiManager: SessionDelegate{
var sessionManager: SessionManager?
override init(){
super.init()
initReachibility()
sessionManager = SessionManager.init(configuration: URLSessionConfiguration.ephemeral, delegate: self)
}
override func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// Call into TrustKit here to do pinning validation
if TrustKit.sharedInstance().pinningValidator.handle(challenge, completionHandler: completionHandler) == false {
// TrustKit did not handle this challenge: perhaps it was not for server trust
// or the domain was not pinned. Fall back to the default behavior
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
func makeRequestAlamofire(route:URL, method:HTTPMethod, autherized:Bool, parameter:Parameters,header:[String:String], callback: #escaping (APIResult<Data>) -> Void){
sessionManager?.request(route,method: method,parameters:parameter, encoding: JSONEncoding.default,headers:headers ).validate(statusCode: 200..<300)
.validate(contentType: ["application/json"]).responseData { response in
//Pin Validtion returner
guard response.error == nil else {
// Display Error Alert
print("Result Pinning validation failed for \(route.absoluteString)\n\n\(response.error.debugDescription)")
return
}
switch response.result {
case .success(let val):
print("Success")
case .failure(let error):
print("Faild")
}
}
}
}
For the full tutorial refer this link.
Alamofire has changed sll pinning code snipped with the new version(Alamofire 5.0).
You should use ServerTrustManager just like below,
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = timeoutIntervalForRequest
let trustManager = ServerTrustManager(evaluators: [
"dev.ehliyetcepte.com": PublicKeysTrustEvaluator(),
"uat.ehliyetcepte.com": DisabledEvaluator(),
"pilot.ehliyetcepte.com": DisabledEvaluator(),
"prod.ehliyetcepte.com": DisabledEvaluator()])
self.session = Session(startRequestsImmediately: true,
configuration: configuration,
delegate: self,
serverTrustManager: trustManager)
I would recommend using TrustKit. It is a dedicated library that works with everything base on NSURLSession, including Alamofire. Depending on your use case it may be as simple as adding a few values to Info.plist.
Certificate pinning, same as any security measure, is not something you should implement yourself, but you should use a proven library.
let serverTrustPolicies: [String: ServerTrustPolicy] = [
// or `pinPublicKeys`
"test.example.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .disableEvaluation
]
let sessionManager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
I found this solution
let session = Session(delegate:CustomSessionDelegate())
session.request....
class CustomSessionDelegate: SessionDelegate {
private static let publicKeyHash = "your_public_key"
let rsa2048Asn1Header:[UInt8] = [
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
]
override func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil);
return
}
if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
// Server public key
guard let serverPublicKey = SecCertificateCopyKey(serverCertificate) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
guard let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey, nil) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let data:Data = serverPublicKeyData as Data
// Server Hash key
let serverHashKey = sha256(data: data)
// Local Hash Key
let publickKeyLocal = type(of: self).publicKeyHash
if (serverHashKey == publickKeyLocal) {
// Success! This is our server
print("Public key pinning is successfully completed")
completionHandler(.useCredential, URLCredential(trust:serverTrust))
return
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
}
}
private func sha256(data : Data) -> String {
var keyWithHeader = Data(rsa2048Asn1Header)
keyWithHeader.append(data)
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
keyWithHeader.withUnsafeBytes {
_ = CC_SHA256($0, CC_LONG(keyWithHeader.count), &hash)
}
return Data(hash).base64EncodedString()
}

How to connect to self signed servers using Alamofire 1.3

I get the below error while connecting to self signed server.
Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “maskeddomain.com” which could put your confidential information at risk." UserInfo=0x7fb6dec259e0 {NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9813, NSUnderlyingError=0x7fb6dbe0dd90 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1202.)"
Looks like Alamofire 1.3 (https://github.com/Alamofire/Alamofire#security) allows disabling this validation. Has anyone implemented this? I'm using Alamofire API's on my swift project, not sure where exactly "Server Trust Policy Manager" needs to be implemented. Please advice.
Manager configuration for Swift 3 or Swift 4 and Alamofire 4:
private static var manager: Alamofire.SessionManager = {
// Create the server trust policies
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .disableEvaluation
]
// Create custom manager
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let manager = Alamofire.SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
return manager
}()
There is a way to change the Server Trust Policy of the Alamofire manager shared instance, but it's not recommended. Instead you should create your own customised instance of the manager. Here is the recommended solution, code is Swift 2.0 with Alamofire from swift-2.0 branch, compiled in Xcode7 beta 5.
Creating customised instance of the manager
Because you will not use the request method on the Alamofire, but use the one on your custom manager instead, you need to think of where to store the manager. What I do is to store it as static in my networking wrapper (the class that utilizes Alamofire and deals with my application networking needs). I set it up like this:
private static var Manager : Alamofire.Manager = {
// Create the server trust policies
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"maskeddomain.com": .DisableEvaluation
]
// Create custom manager
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
let man = Alamofire.Manager(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
return man
}()
Next step is to switch all your calls that use Alamofire.request() with Manager.request(), so you should have something like this:
Manager.request(.GET, "http://stackoverflow.com").responseJSON(
completionHandler: { (_, respose, result) -> Void in
if result.isSuccess {
// enjoy your success
} else if result.isFailure {
// deal with your failure
}
})
If you want to change the shared instance of the manager anyway, go here for more info.
An example is posted right in the README demonstrating exactly how to disable evaluation if you need to do so.
Since you are going to need to create your own Manager instance as well, you'll want to do something like the following:
class NetworkManager {
static let sharedInstance = NetworkManager()
let defaultManager: Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .DisableEvaluation
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
}
This will then allow you to make requests with the NetworkManager.sharedInstance.defaultManager object.
Another approach for my project. The ServerTrustPolicyManager is an open class, and it's serverTrustPolicy function is open too. So it can be override.
// For Swift 3 and Alamofire 4.0
open class MyServerTrustPolicyManager: ServerTrustPolicyManager {
// Override this function in order to trust any self-signed https
open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
return ServerTrustPolicy.disableEvaluation
// or, if `host` contains substring, return `disableEvaluation`
// Ex: host contains `my_company.com`, then trust it.
}
}
Then,
let trustPolicies = MyServerTrustPolicyManager(policies: [:])
let manager = Alamofire.SessionManager(configuration: sessionConfig, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)
UPDATE #2018,01
In order to trigger the ServerTrustPolicyManager, the project's Info.plist needs to be configured. I found the solution, detail at this post, cnoon's comment # 1 Nov 2015.
For example, if there are urls named site1.foo.com, site2.foo.com, ....
Then add App Transport Security Settings -> Exception Domains -> foo.com dictionary, with following entries.
NSExceptionRequiresForwardSecrecy : NO
NSExceptionAllowsInsecureHTTPLoads : YES
NSIncludesSubdomains : YES
More detail you can refer the post.
Anyway, the answer of #cnoon almost full. But I met another trouble of the ssl validation, so I want to put my code here if someone can get help from it.The manager init as:
private var manager: Manager?
// Import the certificates like xxx.cer to your project(anywhere will be fine), then the ServerTrustPolicy.certificatesInBundle() can find them
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: false,
validateHost: true
)
let serverTrustPolicies: [String : ServerTrustPolicy] = [
"sub.server.com": .DisableEvaluation, // because the certificates only add the main domain, so disable evaluation for subdomain
"192.168.0.2:8090": .DisableEvaluation, // the IP address for request data
"www.server.com": serverTrustPolicy
]
manager = Manager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
Then use the manager to request:
// this function in the class which for manager the Alamofire request
public func request(method: Alamofire.Method, _ URLString: URLStringConvertible,
parameters: [String : AnyObject]?) -> Alamofire.Request
{
// we do not need use Alamofire.request now, just use the manager you have initialized
return manager!.request(method, URLString, parameters: parameters,
headers: ["tokenId": UserManager_Inst.tokenID])
}
p.s.: it is the swift 2.3 sample