Как безопасно загружать файлы с помощью Alamofire на локальный сервер, используя TLS и самозаверяющие сертификаты? - PullRequest
0 голосов
/ 03 мая 2020

Я смог успешно загрузить файлы на локальный сервер (реализован в node.js), используя Alamofire 5 с ATS Allow Arbitrary Loads и следующий фрагмент:

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)
}

Я смог переключиться на HTTPS на локальном сервере, и я могу загружать файлы с почтальоном, используя самозаверяющие сертификаты ca / ​​client и server. Я прочитал сообщения для самозаверяющего закрепления сертификата, но я не уверен, что мне нужно закрепить или подтвердить подлинность.

Какова оптимальная практика использования TLS на локальном сервере с самозаверяющими сертификатами и Alamofire?

РЕДАКТИРОВАНИЕ 5/4/20: Следуя предложениям из разных источников Я добился прогресса, добавив следующее:

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
    }
}

И внутри своего класса я добавил:

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)
}()

После добавления выше я смог использовать https для загрузки файлов , Я не уверен, почему я должен установить performDefaultValidation и validateHost на false, чтобы избежать получения Alamofire.AFError.serverTrustEvaluationFailed. Это правильный путь к go? Еще один момент, который я пытаюсь выяснить, почему мне нужен только сертификат CA root для закрепления?

1 Ответ

1 голос
/ 04 мая 2020

Я реализовал нечто подобное:

  1. Скопируйте самозаверяющий сертификат в ваш проект XCode. Давайте назовем этот сертификат «myCert.der»

  2. Настройте безопасный менеджер сеансов Alamofire с вашим подписанным сертификатом. Это будет что-то вроде этого.

    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. Вызовите функцию для настройки вашего безопасного менеджера сеансов: configureAlamoFireSSLPinning()

  4. Сделайте ваши запросы с помощью этого безопасного менеджера сеансов alamofire. Все запросы, сделанные через этого менеджера, будут защищены:

    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)
    
     }
    }
    

    Для получения дополнительной информации вы можете посетить документацию Alamofire по безопасности: https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security

...