如何用requests库验证证书 | Mayx的博客
Author: mayx
Description: 用Python制作的程序怎么样？
Date: 2024-03-16T00:00:00+08:00

16 March 2024 - 字数统计：1657 - 阅读大约需要5分钟 - Hits: Loading...

# 如何用requests库验证证书

by mayx

这是一篇创建于 天前的文章，其中的信息可能已经有所发展或是发生改变。

AI摘要

这篇文章讲述了使用Python的requests库实现类似“SSL Pinning”技术的过程。作者发现直接用requests库操作请求时，获取证书的常见方法不可行，于是通过requests.packages.urllib3的HTTPSConnection连接并修改其connect方法，实现了在发起GET请求时获取服务器的证书，并计算其SHA256指纹。作者提供了一个函数`verify_cert_request`，用于验证网站证书并可作为防抓包策略。文章最后提到，虽然Python作为解释型语言，其代码可被分析，但通过修改依赖库或加密处理可以提高保护程度，防止多数抓包行为。

- 起因
- 实现方案
- 后记

用Python制作的程序怎么样？

#
起因

之前在抓包某些APP的时候，可能会遇到即使信任了抓包软件的CA根证书也无法抓包的情况，听说之所以遇到这种情况是因为那些APP使用了“SSL Pinning”的技术，可以只信任代码中认为可以信任的证书。不过对于逆向之类的事情我并不擅长，这种问题我也不太会解决。但是不能解决问题我可以创造问题啊，Java的APP我不会写，但是我会用Python写，所以今天来看看怎么样用Python实现类似“SSL Pinning”的技术。

#
实现方案

真正的SSL Pinning似乎是通过预置网站所使用的根证书或者中间证书来实现的，这样的好处是即使证书到期换了证书也能继续验证。不过我觉得其实没必要这么麻烦，一般Python程序要连接的后端也没必要在浏览器中调用，大不了就自签一个证书，然后自己验证证书就好了，反正中间人攻击重新签的公钥证书的指纹肯定和原来网站公钥证书的指纹不一样，用这一点就可以判断有没有被抓包。

不过我搜了一下，如果想实现这个功能，首先请求的时候就要获得网站的证书，很多资料都是直接用socket和ssl这两个包实现的，但是在python上请求一般都是用requests，用socket操作有点太麻烦了吧，再问问AI呢？AI给出的回复是：`response.raw.connection.getpeercert()`，结果执行了根本没有这个方法，不愧是只会东拼西凑，这应该是ssl库的函数吧……要么可以用`urllib3.contrib.pyopenssl.ssl.get_server_certificate()`这个方法获取，但是这个方法不是在发起请求的时候获取的证书，而是直接先访问了一下服务器然后直接获取的证书，这样每次调用接口的时候可能就要请求两次服务器了，感觉不怎么好……后来去Stack Overflow上搜了一下，还真有关于类似这个问题的讨论，于是我简单改编了一下，最终效果如下：

    import requests
    import hashlib

    HTTPSConnection = requests.packages.urllib3.connection.HTTPSConnection
    orig_HTTPSConnection_connect = HTTPSConnection.connect
    def new_HTTPSConnection_connect(self):
        orig_HTTPSConnection_connect(self)
        try:
            self.peer_certificate = self.sock.getpeercert(binary_form=True)
        except AttributeError:
            pass
    HTTPSConnection.connect = new_HTTPSConnection_connect

    def verify_cert_request(url):
        with requests.get(url, stream=True, verify=False) as r:
            result = [ hashlib.sha256(r.raw.connection.sock.getpeercert(binary_form=True)).hexdigest(), r.text ]
        return result

    result = verify_cert_request('https://www.baidu.com')
    print(result[0])
    print(result[1][:10])

用这个代码就能获取到请求的网站中证书的指纹了，如果不希望其他人抓包，先自己计算一下自己证书的hash指纹，然后在代码中执行逻辑的时候先判断一下请求网站的指纹是不是自己网站的指纹，如果不是还可以考虑一下反制措施？这样就能实现证书的验证了。

#
后记

不过Python作为解释型语言，代码不是随便看😂？就算用Cython然后加壳啥的调用的库依然不是加密的，大不了修改依赖的库然后让它返回的结果向正确的凑可能也行？不过这样至少能防止绝大多数抓包的人了。

tags: Python - requests - ssl 查看原始文件

#### 推荐文章

Loading...

上一篇：Luckfox Pico Plus使用体验
下一篇：关于旧电脑的使用探索
想问这篇文章
召唤伊斯特瓦尔