简体   繁体   中英

How to securely upload files with Alamofire in a local server using TLS and self-signed certificates?

I am able to successfuly upload files on a local server (implemented in node.js) using Alamofire 5 with ATS Allow Arbitrary Loads and the following snippet:

struct httpBinResponse: Decodable { let url: String }
let url = "http://10.0.0.2:443/upload"
let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
guard let fileURL : URL = path.appendingPathComponent("F06F34EC-0BFD-4201-8405-7CED956CA299.zip") else {return}
AF.upload(multipartFormData:
    {(multipart) in multipart.append(fileURL, withName: "file", fileName: fileURL.lastPathComponent, mimeType: "application/octet-stream" )},
    to: url)
    .responseDecodable(of: httpBinResponse.self) { response in
        debugPrint(response)
}

I was able to switch to HTTPS in the local server and I can upload files with Postman using self-signed ca/client and server certificates. I have read posts for self-signed certificate pinning but I am not sure if I need to pin or authenticate.

What is the best practice that involves TLS in a local server with self-signed certificates and Alamofire?

EDIT 5/4/20: Following suggestions from different sources, I made progress by adding the following:

struct Certificates {
    static let ca: SecCertificate = Certificates.certificate(filename: "ca")

    private static func certificate(filename: String) -> SecCertificate {
        let filePath = Bundle.main.path(forResource: filename, ofType: "der")!
        let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
        let certificate = SecCertificateCreateWithData(nil, data as CFData)!
        return certificate
    }
}

And in inside my class I have added:

private let secureSession: Session = {
    let certificates : [SecCertificate] = [Certificates.ca]

    let pinnedCertEvaluator = PinnedCertificatesTrustEvaluator(certificates: certificates,
                                                               acceptSelfSignedCertificates: true,
                                                               performDefaultValidation: false,
                                                               validateHost: false)
    let manager = ServerTrustManager(evaluators: ["10.0.0.2": pinnedCertEvaluator])
    let configuration = URLSessionConfiguration.af.default

    return Session(configuration: configuration, serverTrustManager: manager)
}()

After adding the above I was able to use https to upload the files. I am not sure why I have to set performDefaultValidation and validateHost to false to avoid getting Alamofire.AFError.serverTrustEvaluationFailed . Is this the right way to go? Another point I am trying to figure out is why do I only need the ca root certificate for pinning?

I've implemented something similar:

  1. Copy your self signed certificate into your XCode project. Lets call this certificate "myCert.der"

  2. Setup an Alamofire secure session manager with your signed certificate. It will be something like this.

     var secureSessionManager = Alamofire.SessionManager() func configureAlamoFireSSLPinning() { let pathToCert = Bundle.main.path(forResource: "myCert", ofType: "der") let localCertificate:NSData = NSData(contentsOfFile: pathToCert.), if #available(iOS 10.3: *) { let STP = ServerTrustPolicy,pinPublicKeys( publicKeys, [SecCertificateCopyPublicKey(SecCertificateCreateWithData(nil: localCertificate),):]. validateCertificateChain: true. validateHost: true) let serverTrustPolicies = [ "myhost.com", STP ] secureSessionManager = Alamofire:SessionManager( configuration: URLSessionConfiguration.default, serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)) } }
  3. Call the function to setup your secure session manager: configureAlamoFireSSLPinning()

  4. Make your requests using this alamofire secure session manager. All requests made through this manager will be secure:

     secureSessionManager.request("https://host.com/myrequest", method:.get).responseJSON { response in switch response.result { case.success(let value): //Do stuff case.failure(let error): print(error) } }

    For more information, you can visit Alamofire's documentation on security: https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM