如何使用 TLS 和自签名证书在本地服务器中使用 Alamofire 安全上传文件?
How to securely upload files with Alamofire in a local server using TLS and self-signed certificates?
我能够使用带有 ATS Allow Arbitrary Loads
的 Alamofire 5 和以下代码段成功地将文件上传到本地服务器(在 node.js 中实现):
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 和服务器证书通过 Postman 上传文件。
我已阅读有关自签名证书固定的帖子,但我不确定是否需要固定或验证。
在具有自签名证书和 Alamofire 的本地服务器中涉及 TLS 的最佳实践是什么?
编辑 2020 年 5 月 4 日:
根据不同来源的建议,我通过添加以下内容取得了进展:
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
}
}
在我的 class 里面我添加了:
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
。这是正确的方法吗?我想弄清楚的另一点是为什么我只需要 ca 根证书来固定?
我已经实现了类似的东西:
将您的自签名证书复制到您的 XCode 项目中。我们称此证书为 "myCert.der"
使用您的签名证书设置一个 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))
}
}
调用该函数来设置您的安全会话管理器:
configureAlamoFireSSLPinning()
使用这个 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
我能够使用带有 ATS Allow Arbitrary Loads
的 Alamofire 5 和以下代码段成功地将文件上传到本地服务器(在 node.js 中实现):
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 和服务器证书通过 Postman 上传文件。 我已阅读有关自签名证书固定的帖子,但我不确定是否需要固定或验证。
在具有自签名证书和 Alamofire 的本地服务器中涉及 TLS 的最佳实践是什么?
编辑 2020 年 5 月 4 日: 根据不同来源的建议,我通过添加以下内容取得了进展:
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
}
}
在我的 class 里面我添加了:
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
。这是正确的方法吗?我想弄清楚的另一点是为什么我只需要 ca 根证书来固定?
我已经实现了类似的东西:
将您的自签名证书复制到您的 XCode 项目中。我们称此证书为 "myCert.der"
使用您的签名证书设置一个 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)) } }
调用该函数来设置您的安全会话管理器:
configureAlamoFireSSLPinning()
使用这个 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