CrazyDailyQuestion icon indicating copy to clipboard operation
CrazyDailyQuestion copied to clipboard

OKhhtp3 如何反抓包

Open MicroKibaco opened this issue 4 years ago • 0 comments

我们在看OKhttp源码的时候,其们可以看到TLS 握手的过程connectTls 方法

private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {
    Address address = route.address();
    SSLSocketFactory sslSocketFactory = address.sslSocketFactory();
    boolean success = false;
    SSLSocket sslSocket = null;
    try {
		// 基于之前建立的Socket建立一个包装对象SSLSocket
		sslSocket = (SSLSocket) sslSocketFactory.createSocket(
                rawSocket, address.url().host(), address.url().port(), true /* autoClose */);
        // 对TLS相关信息进行配置
        ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket);
        if (connectionSpec.supportsTlsExtensions()) {
            Platform.get().configureTlsExtensions(
                    sslSocket, address.url().host(), address.protocols());
        }
        // 进行握手
        sslSocket.startHandshake();
        // 获取SSLSession
        SSLSession sslSocketSession = sslSocket.getSession();
        Handshake unverifiedHandshake = Handshake.get(sslSocketSession);
        // 验证证书对该主机是否有效
        if (!address.hostnameVerifier().verify(address.url().host(), sslSocketSession)) {
            List<Certificate> peerCertificates = unverifiedHandshake.peerCertificates();
            if (!peerCertificates.isEmpty()) {
                X509Certificate cert = (X509Certificate) peerCertificates.get(0);
                throw new SSLPeerUnverifiedException(
                        "Hostname " + address.url().host() + " not verified:"
                                + "\n    certificate: " + CertificatePinner.pin(cert)
                                + "\n    DN: " + cert.getSubjectDN().getName()
                                + "\n    subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert));
            } else {
                throw new SSLPeerUnverifiedException(
                        "Hostname " + address.url().host() + " not verified (no certificates)");
            }
        }
        address.certificatePinner().check(address.url().host(),
                unverifiedHandshake.peerCertificates());
        String maybeProtocol = connectionSpec.supportsTlsExtensions()
                ? Platform.get().getSelectedProtocol(sslSocket)
                : null;
        socket = sslSocket;
        // 获取source及sink
        source = Okio.buffer(Okio.source(socket));
        sink = Okio.buffer(Okio.sink(socket));
        handshake = unverifiedHandshake;
        protocol = maybeProtocol != null
                ? Protocol.get(maybeProtocol)
                : Protocol.HTTP_1_1;
        success = true;
    } catch (AssertionError e) {
        if (Util.isAndroidGetsocknameError(e)) throw new IOException(e);
        throw e;
    } finally {
        if (sslSocket != null) {
            Platform.get().afterHandshake(sslSocket);
        }
        if (!success) {
            closeQuietly(sslSocket);
        }
    }
}
  • 基于之前建立的 Socket 建立包装类 SSLSocket
  • 对 TLS 相关信息进行配置
  • 通过 SSLSocket 进行握手 最后 验证一些证书相关信息 ,我们在这个步骤,进行证书的锁定,给我们的域名 域名host 添加 sha256的证书,配置后,这个域名的请求就不能被抓包了。因为开启抓包后,根证书是 charles 的公钥,跟期望的 sha256 匹配不上。

MicroKibaco avatar Oct 21 '20 10:10 MicroKibaco