网络安全通信:HTTPS配置、SSL Pinning实现、证书校验、WebView安全配置

大家好,我是你们的Android安全讲师。今天我们来聊聊网络安全通信这块硬骨头。

说实话,我见过太多App因为网络通信没做好而出事的案例。有一次我接手一个金融类App的审计,发现它居然还在用HTTP明文传输用户的银行卡号。我当时就愣住了——这等于把用户的密码写在明信片上寄出去啊。

好,我们直接进入正题。网络通信安全,说白了就是解决三个问题:通信内容不被偷看、不被篡改、对方确实是你要找的人。Android上怎么做?我们一个一个来看。

一、HTTPS配置:别再用HTTP了

HTTPS不是可选项,是必选项。我个人习惯在项目一开始就把网络层强制为HTTPS。

在Android中,配置HTTPS其实很简单。你需要在AndroidManifest.xml中声明网络安全配置:

<application
    android:networkSecurityConfig="@xml/network_security_config"
    ...>

然后在res/xml/network_security_config.xml中写:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

这里cleartextTrafficPermitted="false"就是禁止明文HTTP流量。嗯,这一步做完,你的App就不会偷偷走HTTP了。

⚠️ 注意: 如果你在开发阶段需要调试本地服务器,可以单独为10.0.2.2(模拟器)或localhost开启明文,但上线前一定要删掉。

二、SSL Pinning:防中间人攻击的杀手锏

HTTPS就够了吗?不够。你想想看,如果用户的设备上被安装了恶意CA证书(比如某些公司监控员工手机),那HTTPS照样能被中间人攻击。

SSL Pinning就是解决这个问题的。它让App只信任你指定的证书或公钥,而不是系统里所有的CA证书。

我曾经在一个银行项目中,因为没做SSL Pinning,测试人员用Fiddler就轻松抓到了所有API请求。从那以后,我再也不敢省略这一步。

实现方式有两种:

  1. 证书Pinning:把服务器证书的哈希值硬编码到App里
  2. 公钥Pinning:只固定公钥,证书过期时不用更新App

我用OkHttp举个例子:

// 获取证书的SHA-256哈希值
CertificatePinner certificatePinner = new CertificatePinner.Builder()
    .add("api.yourdomain.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
    .build();

OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(certificatePinner)
    .build();

这里有个坑——备份证书。我建议你至少固定两个证书:当前证书和备用证书。万一证书轮换,你的App不会直接挂掉。

💡 小技巧: 可以用openssl s_client -connect api.yourdomain.com:443 -showcerts来获取服务器证书的哈希值。

三、证书校验:别让代码骗了你

有些开发者为了省事,会写一个TrustAllCertificates的类。我见过最离谱的代码是这样的:

// ❌ 千万不要这样做!
TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }
};

这段代码等于告诉系统:任何证书我都信。你想想看,这跟没锁门有什么区别?

正确的做法是使用系统默认的TrustManager,或者自己实现校验逻辑:

// ✅ 正确的证书校验
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

如果你需要自签名证书,可以把证书放到res/raw目录下,然后用自定义的TrustManager加载它。

🔑 核心原则: 永远不要信任所有证书。只信任你明确指定的证书或CA。

四、WebView安全配置:最容易忽视的漏洞

WebView是Android安全的重灾区。我审计过的App里,十个有八个WebView配置有问题。

最常见的问题有三个:

  • 允许JavaScript与Native交互(addJavascriptInterface)
  • 允许加载HTTP内容
  • 允许文件访问

来看一个安全的WebView配置:

WebView webView = findViewById(R.id.webview);
WebSettings settings = webView.getSettings();

// 关闭文件访问
settings.setAllowFileAccess(false);
settings.setAllowFileAccessFromFileURLs(false);
settings.setAllowUniversalAccessFromFileURLs(false);

// 只允许HTTPS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
}

// 谨慎使用JavaScript
settings.setJavaScriptEnabled(true); // 只在必要时开启

// 不要随意添加JavaScript接口
// webView.addJavascriptInterface(new JsBridge(), "bridge"); // ❌ 除非你非常清楚风险

还有一个容易被忽略的点:WebView的证书校验。默认情况下,WebView使用系统的证书链。但如果你用了自定义的WebViewClient,一定要重写onReceivedSslError方法:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        // ❌ 不要调用 handler.proceed()
        // ✅ 应该调用 handler.cancel()
        handler.cancel();
    }
});

我曾经见过一个电商App,WebView里onReceivedSslError直接调了handler.proceed()。结果用户连到公共WiFi时,所有购物信息都被抓走了。

知识体系总览

下面这张图帮你理清今天讲的内容:

网络安全通信 HTTPS配置 SSL Pinning 证书校验 WebView安全 networkSecurityConfig cleartextTrafficPermitted=false CertificatePinner 公钥/证书哈希固定 TrustManagerFactory 禁止TrustAllCertificates 关闭文件访问 onReceivedSslError→cancel 核心目标:防窃听、防篡改、防冒充 四者缺一不可,形成完整防护链

你看,这四个方面其实是环环相扣的。HTTPS是基础,SSL Pinning加固了信任链,证书校验防止了代码层面的绕过,WebView安全则堵住了UI层的漏洞。

最后说一句:安全不是一次性配置,而是持续的过程。每次更新依赖库、每次更换服务器证书,都要重新检查这些配置是否还生效。

📌 课后自检清单:
  • 你的App是否完全禁止了HTTP?
  • SSL Pinning是否配置了至少两个备用证书?
  • 有没有任何地方使用了TrustAllCertificates?
  • WebView的onReceivedSslError是否调用了cancel()?

公众号:蓝海资料掘金营,微信deep3321