网络安全通信:HTTPS配置、SSL Pinning实现、证书校验、WebView安全配置
大家好,我是你们的老朋友。今天我们来聊聊网络安全通信这个话题。说实话,这是Android安全开发里最容易被忽视,但又最容易出大问题的一块。
我记得刚入行那会儿,有个同事把HTTPS配置搞错了,结果用户数据在传输过程中被中间人截获。嗯,那场面,真是惨不忍睹。从那以后,我对网络通信这块就格外上心。
今天我会从四个维度来拆解:HTTPS怎么配、SSL Pinning怎么玩、证书校验有哪些坑、WebView怎么安全配置。每个点我都会结合自己的实战经验来讲。
一、HTTPS配置:别以为配了就安全了
很多人觉得,只要用了HTTPS就万事大吉。其实不然。我见过太多项目,HTTPS配了,但用的是自签名证书,或者干脆关闭了证书校验。
先看一个标准的HTTPS配置示例:
// 在AndroidManifest.xml中配置网络安全策略
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.yourdomain.com</domain>
<trust-anchors>
<certificates src="@raw/ca_cert"/>
</trust-anchors>
</domain-config>
</network-security-config>
这里有几个关键点:
- cleartextTrafficPermitted="false":强制使用HTTPS,不允许明文传输
- includeSubdomains="true":子域名也受保护
- trust-anchors:指定信任的CA证书
cleartextTrafficPermitted="true"。我曾经在一个金融App里看到这个配置,吓得我赶紧联系了对方的安全团队。
二、SSL Pinning:给证书加把锁
SSL Pinning,说白了就是让App只信任特定的证书或公钥。为什么要这么做?因为默认的证书校验机制存在一个漏洞:只要CA签发的证书都能通过验证。如果CA被攻破,或者有人伪造了CA证书,你的通信就危险了。
我个人习惯用公钥固定(Public Key Pinning),因为证书会过期,但公钥不会。来看代码:
public class PinningTrustManager implements X509TrustManager {
private static final String PINNED_PUBLIC_KEY = "SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
if (chain == null || chain.length == 0) {
throw new CertificateException("证书链为空");
}
// 获取服务器证书的公钥
PublicKey serverKey = chain[0].getPublicKey();
String serverKeyHash = hashPublicKey(serverKey);
// 与固定的公钥比较
if (!PINNED_PUBLIC_KEY.equals(serverKeyHash)) {
throw new CertificateException("公钥不匹配,可能存在中间人攻击");
}
}
private String hashPublicKey(PublicKey key) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(key.getEncoded());
return Base64.encodeToString(digest, Base64.NO_WRAP);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256算法不可用", e);
}
}
}
三、证书校验:别跳过,也别乱写
证书校验是HTTPS安全的核心。但很多开发者为了省事,直接写了个空实现。你想想看,这跟裸奔有什么区别?
正确的做法是:
- 校验证书链:从服务器证书到根证书,每一级都要验证
- 校验主机名:确保证书的CN或SAN与请求的域名匹配
- 校验有效期:证书是否在有效期内
- 校验吊销状态:通过CRL或OCSP检查证书是否被吊销
来看一个完整的校验示例:
public class CustomHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
try {
// 获取服务器证书
Certificate[] certs = session.getPeerCertificates();
if (certs == null || certs.length == 0) {
return false;
}
// 检查主机名是否匹配
X509Certificate cert = (X509Certificate) certs[0];
String cn = getCN(cert);
if (!hostname.equals(cn)) {
// 检查SAN扩展
Collection<List<?>> san = cert.getSubjectAlternativeNames();
if (san != null) {
for (List<?> entry : san) {
if (entry.get(1).toString().equals(hostname)) {
return true;
}
}
}
return false;
}
return true;
} catch (SSLPeerUnverifiedException e) {
return false;
}
}
}
四、WebView安全配置:最容易忽视的漏洞
WebView的安全配置,说实话,是Android安全里最容易被忽视的一块。很多人觉得WebView就是个浏览器,能有什么问题?问题大了去了。
先看一个不安全的配置:
// ❌ 不安全的配置
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowContentAccess(true);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false; // 允许所有URL
}
});
这个配置的问题在于:
- JavaScript启用:可能被XSS攻击利用
- 文件访问开启:攻击者可以读取本地文件
- 内容访问开启:可能被用来访问Content Provider
- URL不校验:可能跳转到恶意网站
正确的配置应该是这样的:
// ✅ 安全的配置
WebView webView = findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
// 按需启用JavaScript
settings.setJavaScriptEnabled(false); // 如果不需要,就关掉
// 关闭不必要的访问
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
settings.setAllowFileAccessFromFileURLs(false);
settings.setAllowUniversalAccessFromFileURLs(false);
// 设置安全的WebViewClient
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
// 只允许加载HTTPS链接
if (url.startsWith("https://")) {
return false;
}
return true;
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// 不要调用handler.proceed(),应该拒绝
handler.cancel();
}
});
addJavascriptInterface() 暴露Java对象给JavaScript。除非你非常清楚自己在做什么,并且做了严格的权限控制。我曾经因为这个接口被滥用,导致用户数据泄露。
五、知识体系总览
说了这么多,我们来梳理一下整个网络安全通信的知识体系。下面这张图可以帮你快速理解各个模块之间的关系:
从这张图可以看出,网络安全通信不是单一的技术点,而是一个完整的体系。HTTPS配置是基础,SSL Pinning是加固,证书校验是保障,WebView安全是补充。四者缺一不可。
好了,今天就聊到这里。网络安全通信这块内容不少,但每个点都很关键。希望你能把这些知识用到实际项目中去,别让用户数据在传输过程中出问题。
公众号:蓝海资料掘金营,微信deep3321