抓包技术分析及SSL PINNING保护方案

要分析抓包的技术首先要介绍数字证书是什么,一切的抓包手段都是围绕数字证书做文章

数字证书

TLS 握手的作用之一是身份认证,被验证的一方需要提供一个身份证明,在 HTTPS 的世界里,这个身份证明就是 TLS 证书,或者称为 数字证书

JDK 中用 java.security.cert.X509Certificate 来表示一个证书,它继承自抽象类 java.scurity.cert.Certificate,通过 X509Certificate 我们可以获取证书的信息,例如x509Certificate.getSubjectDN().getName()


数字证书构成.png

x509Certificate.getSubjectDN().getName()获取到的是证书的Subject's Name的信息即证书拥有者,内容是一组符合 X.500 规范的 DN(Distinguished Name)

CN=*,OU=IT Department,O=China Merchants Bank Co., Ltd,L=Shenzhen,C=CN

这是从我们证书中获取到的信息,DN的属性含义如图所示

DN参数

通过命令openssl x509 -in base64.cer –text 查看证书信息,输出如图所示
可以看出,一个 Certificate 由 Data 和 Signature 两部分组成。其中 Data 包含的内容有:
证书版本号:X.509v3
序列号:一个 CA 机构内是唯一的,但不是全局唯一
签名算法:签名的计算公式为RSA(sha256(Data), IssuerPrivateKey)
签发者:DN(Distinguished Name)
有效期:证书的有效期间 [Not Before, Not After]
证书拥有者:也是一个 DN公钥长度一般是 2048bit,1024bit已经被证明不安全
扩展字段:证书所携带的域名信息会配置在 SAN 中(X509v3 Subject Alternative Name)
Signature 位于证书最末尾,签名算法 sha256WithRSAEncryption 在 Data 域内已经指明 ,而 RSA 进行非对称加密所需的私钥(Private Key)则是由 Issuer 提供,Issuer 是一个可以签发证书的证书,由证书权威 CA 提供,CA 需要保证证书的有效性。
因为 Signature 是 RSA 算法生成的,那么客户端拿到 TLS 证书之后,需要 Issuer 的公钥(Public Key)才能解码出 Data 的摘要。
然而证书只携带了 Issuer 的 DN,并没有公钥,为了弄清楚客户端如何获取公钥,我们需要先搞明白 Certificate Chain(证书链)。


证书信息

证书链

一个完整的证书链一般由三种类型的证书组成

  • Root Certificate (DigiCert Global Root CA) :
    根证书
    Root Certificate是由Root CAs 发布,一个Root CAs 下包含多个Intermediate CAs ,同理一个Root Certificate下可以包含多个Intermediate Certificate。根证书是CA自己的证书,是证书验证链的开头
  • Intermediate Certificate (DigiCert SHA2 Secure Server CA):
    中间证书或者叫做中介证书
    Intermediate Certificate是由Intermediate CAs 发布,一个Intermediate CAs 下可以包含多个Intermediate CAs ,同理一个Intermediate Certificate下可以包含多个Intermediate Certificate也可以包含End-entity Certificate。CA会使用Intermediate Certificate 替代Root Certificate去做服务器端的证书签名,确保根证书密钥绝对不可访问
  • End-entity Certificate (user.cmbchina.com):
    终端证书即用户证书
    包含用来加密传输数据的公钥的证书,是HTTPS中使用的证书。 End-entity Certificate上面几级证书都是为了保证End-entity Certificate未被篡改,保证是CA签发的合法证书,进而保证End-entity Certificate中的公钥未被篡改


    证书链

证书链验证

1.客户端得到服务端返回的证书,通过读取得到 服务端证书的发布机构(Issuer)
2.客户端去操作系统查找这个发布机构的的证书,如果是不是根证书就继续递归下去直到拿到根证书。
3.匹配客户端保存的可信任CA与根证书的CA,确保根证书的合法性
4.用 根证书的公钥 去 解密验证 上一层证书的合法性,再拿上一层证书的公钥去验证更上层证书的合法性;递归回溯。
5.最后验证服务器端的证书是 可信任

证书链验证

关于证书链信任认证过程可以参考我的另一篇文档

抓包原理-中间人攻击

前面基础性内容已经铺垫完毕,现在正式分析抓包技术
根据流程可以得出需要让中间人攻击生效,必须让客户端的证书连验证能够通过,并且现在几乎所有攻击手段都是从这入手,实现原理上可以分为两大类:
1.攻击客户端CA信任库,让系统在误认为伪证书是可以信任的,从而向中间人发送信息。手段包括
手机系统中安装伪证书
root手段导入伪证书至证书库
修改rom中系统证书库并烧录系统
例如Charles,Burp,Magisk,Packet Capture(VPN)都是使用这种方法
SSL PINING正是对抗这种技术的方法

抓包流程

2.通过脚本或者框架hook验证证书的方法,主要手段有:
修改系统checkServerTrusted或者TrustManager等涉及验证或者整理证书的相关代码,返回他们需要的结果
针对有自己的证书验证逻辑的第三方框架例如OKHttp,则hook修改CertificationPinner等方法
APP使用自己封装的通信方法,则通过逆向代码hook相关方法
Xposed+JustTrustMe或者Frida使用的是这种方法,针对这种技术则要避免将涉及通信的代码暴露,可以使用混淆,加壳等多种手段

hook脚本代码

SSL PINNING与双向认证

绿色表示ssl pinning在正常HTTPS通信过程中增加的操作
红色表示双向认证在正常HTTPS通信过程中增加的操作


ssl pinning及双向认证流程
ssl pinning与系统认证的区别

SSL PINNING本地证书管理

SSL PINNING唯一缺点即是如何对本地绑定的证书进行更新,针对该问题研究了一种解决方案方案:

  • 证书服务器:搭建一个CA服务器专门用于更新证书或者在验证证书时通过访问CA服务器验证
  • 与证书服务器通信内容及证书间比对都采用不可逆加密信息,防止中间人拿到通信内容反推出明文
  • 建立客户端及证书服务器端黑名单,尽可能减少与通信次数并增加中间人攻击成本
  • 证书服务器与客户端采用相同加密算法,保证加密后信息一致


    证书服务器

Hook对抗方案

在攻击手段中,hook代码是一个较难防范的点,针对常用的Xposed框架可以做一下防范措施:

  • 检测进程中使用so名中包含关键"hack|inject|hook|call" 的信息


  • 检测手机是否被root:含有su程序和ro.secure是否为1


  • 防止被Hook的方式就是可以查看XposedBridge这个类,有一个全局的hook开关,所有有的应用在启动的时候就用反射把这个值设置成true,这样Xposed的hook功能就是失效了

  • Xposed的hook原理的就是在程序启动都注入jar功能,所以安装hook模块之后,每个应用内部都包含了这个Xposed功能jar,就相当于你的应用中有了Xposed的所有功能类,所以在应用中反射Xposed的类是可以成功的


  • 如果应用被Xposed进行hook操作之后,抛出的异常堆栈信息中就会包含Xposed字样,所以可以通过应用自身内部抛出异常来检测是否包含Xposed字段来进行防护


    image.png
  • 如何在代码中执行shell命令并返回结果

public static ArrayList<String> executeCommand(String[] shellCmd){
        String line = null;
        ArrayList<String> fullResponse = new ArrayList<String>();
        Process localProcess = null;
        try {
            Log.d("gscgsc","excute cmd");
            localProcess = Runtime.getRuntime().exec(shellCmd);
        } catch (Exception e) {
            return null;
        }
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
        BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
        try {
            while ((line = in.readLine()) != null) {
                Log.d("gscgsc","Line received: " + line);
                fullResponse.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.d("gscgsc","–> response was: " + fullResponse);
        return fullResponse
}

SSL PINING实现

String hostname = "xxx.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
        .add(hostname, "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
        .add(hostname, "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
        .add(hostname, "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")
        .build();

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

Request request = new Request.Builder()
        .url("https://" + hostname)
        .build();

client.newCall(request).execute();

SSL PINING实现原理

证书校验时机
private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {
    //包装socket
    sslSocket = (SSLSocket) sslSocketFactory.createSocket(
            rawSocket, address.url().host(), address.url().port(), true /* autoClose */);
    //配置socket参数
    ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket);
    //建立握手
    sslSocket.startHandshake();
    Handshake unverifiedHandshake = Handshake.get(sslSocket.getSession());
    //证书校验
    address.certificatePinner().check(address.url().host(),
            unverifiedHandshake.peerCertificates());
    //检验无异常则保存连接
    String maybeProtocol = connectionSpec.supportsTlsExtensions()
            ? Platform.get().getSelectedProtocol(sslSocket)
            : null;
}

//校验证书与本地证书
public void check (String hostname, List < Certificate > peerCertificates)
throws SSLPeerUnverifiedException {
    for (int p = 0, pinsSize = pins.size(); p < pinsSize; p++) {
        //加密后本地证书的存储
        Pin pin = pins.get(p);
        //sha256加密
        if (pin.hashAlgorithm.equals("sha256/")) {
            if (sha256 == null) sha256 = sha256(x509Certificate);
            if (pin.hash.equals(sha256)) return; // Success!
        }
        //sha1加密
        else if (pin.hashAlgorithm.equals("sha1/")) {
            if (sha1 == null) sha1 = sha1(x509Certificate);
            if (pin.hash.equals(sha1)) return; // Success!
        }
    }
    //校验失败抛出异常
    throw new SSLPeerUnverifiedException(message.toString());
}

结果如下


结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352