akaDuality / Sber3dsWithCustomCert

2 stars 0 forks source link

Разрашаем Сбербанку проходить 3ds

15 февраля 2023 года у Сбера кончится сертификат и надо переходить на самоподписный. Это ведет к изменениям в коде, пример решения в этом репозитории.

В примере проверяю доступность sberbank.ru, у него такое же состояние как и у экранов 3ds.

Info.plist

Скорее всего у вас уже стоит этот флаг в Info.plist: он нужен чтобы вообще уметь хоть что-то грузить в WKWebView. На ревью Apple спросит зачем вам, расскажите про 3ds.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

Подставляем правильный сертификат

Берем отсюда https://www.gosuslugi.ru/crt. Качайте андроидный сертификат, потому что для iOS он выдает профиль, а он нам не нужен.

Конвертируем .cer в .der, потому что iOS только в .der умеет работать.

openssl x509 -in russian_trusted_root_ca.cer -outform der -out certificate.der

Если вы почему то доверяете мне, а не минцифре, то можете сразу взять готовый

certificate.der

Добавляете его в проект, линкуете так, чтобы он попал в бандл.

Дополнительная проверка сертификата

Все экраны будут проходить челендж, но Сбербанк не сможет пройти дефолтные проверки. Поэтому нам надо проверять сертификат вручную.

override func viewDidLoad() {
    super.viewDidLoad()

    webView.navigationDelegate = self

    let sber = URL(string: "https://sberbank.ru")!
    webView.load(URLRequest(url: sber))
}

extension ViewController: WKNavigationDelegate {
    func webView(
        _ webView: WKWebView,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        DispatchQueue.global(qos: .background).async {
            guard let serverTrust = challenge.protectionSpace.serverTrust else {
                return completionHandler(.performDefaultHandling, nil)
            }

            if self.checkValidity(of: serverTrust) {
                // Allow our sertificate
                completionHandler(.useCredential, URLCredential(trust: serverTrust))
            } else {
                // Default check for another connections
                completionHandler(.performDefaultHandling, nil)
            }
        }
    }

    private func checkValidity(of serverTrust: SecTrust) -> Bool {
        SecTrustSetAnchorCertificates(serverTrust, self.certificates as CFArray);
        SecTrustSetAnchorCertificatesOnly(serverTrust, true);

        var error: CFError?
        let isTrusted = SecTrustEvaluateWithError(serverTrust, &error);

        return isTrusted
    }
}

Готово

Запускайте проект, сайт сбера должен открыться

Вопросы