android反抓包

####一开始以为很简单

Android7.0以下
第一步
https://juejin.im/post/5cb98386e51d456e2c24851d
client = new OkHttpClient.Builder() .proxy(Proxy.NO_PROXY) .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .build();

第二步
public static boolean isWifiProxy(Context context) {
final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
String proxyAddress;
int proxyPort;
if (IS_ICS_OR_LATER) {
proxyAddress = System.getProperty(“http.proxyHost”);
String portStr = System.getProperty(“http.proxyPort”);
proxyPort = Integer.parseInt((portStr != null ? portStr : “-1”));
} else {
proxyAddress = android.net.Proxy.getHost(context);
proxyPort = android.net.Proxy.getPort(context);
}
return (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1);
}

android7.0以上
https://blog.csdn.net/alcoholdi/article/details/106455192

####然而,抓包却可以使用drony破掉,drony代理了手机所有的流量

第三步:
自带证书走起
从运维得到 xxxxx.pem
然后使用openssl转换成cer证书
openssl x509 -outform der -in xxxxx.pem -out ClientCertificate.cer
打印cer证书得到字符串
keytool -printcert -rfc -file ClientCertificate.cer

链接参考:
android设置反抓包:
https://juejin.im/post/5d8c593ee51d45783544b9ac
https://www.jianshu.com/p/cc7ae2f96b64
转换证书:
https://www.anquanke.com/post/id/201219

目的是让客户端验证服务端的https证书
最后会报网络错误
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

####最后:

####哈哈,抓包如果还想破也是可以的,需要反编译app,然后找到cer证书,在charles上设置该证书,所以要把cer证书藏得深一点。

####flutter上的做法
charles 只要开了ssl后:

1
2
3
client2.findProxy = (uri) {
return "PROXY 10.10.18.4:8888; PROXY 10.10.21.6:8888;";
};
1
2
[DioErrorType.DEFAULT]: HandshakeException: Handshake error in client (OS Error: 
CERTIFICATE_VERIFY_FAILED: self signed certificate in certificate chain(handshake.cc:354))

加以下的true后,可以抓到包

1
2
3
4
5
6
client2.badCertificateCallback = (X509Certificate cert, String host, int port){
return true;
};
client2.badCertificateCallback = (X509Certificate cert, String host, int port){
return false;
};

[DioErrorType.DEFAULT]: HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: self signed certificate in certificate chain(handshake.cc:354))

1
2
3
4
5
6
7
Future<HttpClient> getHttpClient() async {
ByteData data = await rootBundle.load('images/ClientCertificate.pem');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
HttpClient httpClient = new HttpClient(context: context);
return httpClient;
}

调用的地方

dio = Dio(options);
HttpClient client2 = await getHttpClient();
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
client2.findProxy = (uri) {
return “PROXY 10.10.18.4:8888; PROXY 10.10.21.6:8888;”;
};
client2.badCertificateCallback = (X509Certificate cert, String host, int port){
return false;
};
return client2;
};

完整

####最后验证了,如果不开proxy,怎么设置都可以顺利请求数据

https://book.flutterchina.club/chapter10/http.html
证书校验
Https中为了防止通过伪造证书而发起的中间人攻击,客户端应该对自签名或非CA颁发的证书进行校验。HttpClient对证书校验的逻辑如下:

  1. 如果请求的Https证书是可信CA颁发的,并且访问host包含在证书的domain列表中(或者符合通配规则)并且证书未过期,则验证通过。
  2. 如果第一步验证失败,但在创建HttpClient时,已经通过SecurityContext将证书添加到证书信任链中,那么当服务器返回的证书在信任链中的话,则验证通过。
  3. 如果1、2验证都失败了,如果用户提供了badCertificateCallback回调,则会调用它,如果回调返回true,则允许继续链接,如果返回false,则终止链接。
    综上所述,我们的证书校验其实就是提供一个badCertificateCallback回调,下面通过一个示例来说明。
    上面几句话验证过正确
    其实,如果要防抓包的话直接一句代码就好,正常请求是可以work,只要代理并且尝试用ssl proxying,那么都禁止即可
    client2.badCertificateCallback = (X509Certificate cert, String host, int port){
    return false;
    };

最后保险再加一道
import ‘package:http_certificate_pinning/http_certificate_pinning.dart’;
http_certificate_pinning: ^1.0.3
List allowedSHAFingerprints = [‘24:AE:ED:0F:06:35:A9:D5:77:C4:A9:66:D9:56:33:27:97:87:36:4C:83:DF:96:55:FE:8E:A6:04:26:D4:8C:1E’].toList();
dio.interceptors.add(CertificatePinningInterceptor(allowedSHAFingerprints));
这种方式不好,原因如下

#####最新实验出来的 flutter

#####这种会导致https线上跑的时候卡顿,原因是每个api接口都去请求一次服务器验证,很慢,1s或者2s时间

1
2
3
if (Application.baseUrl.startsWith('https')) {
dio.interceptors.add(CertificatePinningInterceptor([Application.HTTPS_FINGERPRINT].toList()));
}

//防抓包 用dio本身的方式,实际上跟okhttp做法一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
getHttpClient().then((value) => {
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
HttpClient httpClient = value;
return httpClient;
}
});
//获取httpClient
Future<HttpClient> getHttpClient() async {
SecurityContext context = SecurityContext();
try {
ByteData data = await getCert();
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
} catch (e) {
}
HttpClient httpClient = HttpClient(context: context);
return httpClient;
}

//获取证书

1
2
3
Future<ByteData> getCert() async {
return await rootBundle.load('images/ClientCertificate.pem');
}

第二种防抓包只要攻击者设置了代理抓包,就会报错CERTIFICATE_VERIFY_FAILED,原因对方没我们的cert

####kotlin版本

1
2
3
4
5
builder.proxy(Proxy.NO_PROXY);

X509TrustManager trustManager = HttpTrustManager.createTrustManager(); builder.sslSocketFactory(HttpTrustManager.createSslSocketFactory(trustManager)
, trustManager);
OkHttpClient client = builder.build();