13

我正在创建一个访问 HTTPS Web 服务的 iPad 应用程序。我想实施固定,但遇到了问题。

此类创建 Alamofire 管理器(主要取自文档):

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

此函数进行调用:

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

证书保存在项目中,并显示在“目标 > 构建阶段 > 复制捆绑资源”下。

我目前每次发出请求时都会收到以下错误(来自 else 块testPinning()):

Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://www.google.co.uk/, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://www.google.co.uk/})
4

3 回答 3

10

首先,您需要下载证书。最好的方法是在 Firefox 浏览器上下载证书。

步骤1

转到您的网页/API 并单击锁定图标以获取证书。

在此处输入图像描述

第2步

点击查看证书

在此处输入图像描述

第 3 步

单击证书字段选项卡的第一部分,然后单击导出

在此处输入图像描述

第4步

选择格式:- DER

在此处输入图像描述

第 5 步

将文件拖放到您的 XCode 项目中

在此处输入图像描述

第 6 步

在“目标 > 构建阶段 > 复制捆绑资源”下添加证书

在此处输入图像描述

第 7 步

添加网络管理器文件。将您的网址替换为 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)
         )

     }
 }

第 8 步

添加文件以获取会话管理器

import Foundation
import Alamofire
import SwiftyJSON

class APIPinning {

    private static let NetworkManager = MYPNetworkManager()

    public static func getManager() -> SessionManager {
        return NetworkManager.Manager!
    }
 }

第 9 步

在 Alamofire 上使用此会话管理器,例如:-

 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")
        }
}
}
于 2019-04-29T11:39:43.813 回答
10

因此,问题在于证书以错误的格式保存。

ServerTrustPolicy.certificatesInBundle()根据扩展列表查找捆绑包中的所有证书,然后尝试使用SecCertificateCreateWithData. 根据其文档,此功能:

如果 data 参数中传递的数据不是有效的 DER 编码 X.509 证书,则返回 NULL

当您在 Firefox 中导出证书时,文件浏览器底部会弹出一个“格式”弹出窗口。选择“X.509 证书 (DER)”,您应该为此目的获得正确格式的证书。

于 2016-01-05T16:11:38.733 回答
1

在 Alamofire +5 版之后发生了很大的变化,我将在这里列出我为固定证书所做的工作。我的目标是 Moya,因为 Moya 作为 Alamofire 之上的一层,适用于 Alamofire 的东西应该适用于 Moya。

首先要获得服务器证书,您需要在浏览器中打开它,然后单击锁定图标 然后您需要单击证书,如屏幕截图所示。 在此处输入图像描述 之后,您需要将此证书拖到您的桌面或下载它的任何地方,请查看下面的屏幕截图。 在此处输入图像描述 然后,您需要使用在 Xcode 检查屏幕截图中添加文件将其添加到您的项目中。 在此处输入图像描述 这是我的 Alamofire 代码:

var session: Session!

class ViewController: UIViewController {

func testPinning() {


let evaluators: [String: ServerTrustEvaluating] = [
    "stackoverflow.com": PublicKeysTrustEvaluator()
]

let manager = ServerTrustManager(evaluators: evaluators)

session = Session(serverTrustManager: manager)


session
    .request("https://stackoverflow.com/questions/34611112/certificate-pinning-in-alamofire/55902588#55902588", method: .get)
    .validate()
    .response(completionHandler: { [weak self] response in
        switch response.result {
        case .success:
            print(response.data)
        case .failure(let error):
            switch error {
            case .serverTrustEvaluationFailed(let reason):
                // The reason here is a place where you might fine-tune your
                // error handling and possibly deduce if it's an actualy MITM
                // or just another error, like certificate issue.
                //
                // In this case, this will show `noRequiredEvaluator` if you try
                // testing against a domain not in the evaluators list which is
                // the closest I'm willing to setting up a MITM. In production,
                // it will most likely be one of the other evaluation errors.
                print(reason)
            default:
                print("default")
            }
        }
    })

}

对于 Moya,您需要将该会话添加到您的 moya 提供程序。

let evaluators: [String: ServerTrustEvaluating] = [
    "stackoverflow.com": PublicKeysTrustEvaluator()
]

let manager = ServerTrustManager(evaluators: evaluators)

session = Session(serverTrustManager: manager)


let provider = MoyaProvider<YourStackOVerflowProvider>(
    session: session
)


provider.request(.pluginManger) { response in
    switch response {
    case .failure(let err):
        print(err)
    case .success(let response):
        print(response)
    }
}
于 2021-05-30T08:48:35.910 回答