python安全开发军规之二:防止中间人攻击

背景

当我们在做开发的时候,很多时候都需要抓取我们收发的数据包,比如android开发的时候,我会在本地打开fiddler,查看app的所有http请求;有的时候为了调试方便,还会修改hosts文件,将某一域名指向特定的IP……在前面两个例子中,其实是中间人攻击(man in the middle attack,简称MITM)两种常用手段,第一种是代理劫持,第二种是DNS劫持,随着网络技术的发展,还出现了很多其它的中间人攻击手段。

普通程序员的写法
In [6]:
import requests
import urllib3
urllib3.disable_warnings()
response=requests.get('https://randomuser.me/api/', verify=False)
print(response.text)
{"results":[{"gender":"male","name":{"title":"mr","first":"clifton","last":"holmes"},"location":{"street":"8035 victoria road","city":"kingston upon hull","state":"dorset","postcode":"M5 7TF","coordinates":{"latitude":"11.7838","longitude":"-4.3395"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"clifton.holmes@example.com","login":{"uuid":"268ce64b-261b-4f8d-a849-2c9df6c5deff","username":"brownmeercat231","password":"liverpool","salt":"jyfT0FYl","md5":"a2288b18510a39d3587da4c7a9cf356a","sha1":"f15f99dbfda2b9557f465886727cef271ac012cd","sha256":"14a9be291a3169a973e025a11cdd6ff4705ce30fe12d9b553d3c2e9d15245229"},"dob":{"date":"1986-04-24T08:41:51Z","age":33},"registered":{"date":"2011-10-01T05:51:15Z","age":7},"phone":"016973 84729","cell":"0793-654-443","id":{"name":"NINO","value":"GM 65 05 50 I"},"picture":{"large":"https://randomuser.me/api/portraits/men/82.jpg","medium":"https://randomuser.me/api/portraits/med/men/82.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/82.jpg"},"nat":"GB"}],"info":{"seed":"cadfce3bcdc5fe91","results":1,"page":1,"version":"1.2"}}

程序运行良好,完美地实现了所需要的功能,不是吗?

QA有话说

是的,程序运行得没错?可是代码中有两处安全问题,一是将 verify 设置为 False,使Requests 忽略了对 SSL 证书的验证;二是隐藏了urllib3抛出的证书校验失败的警告。这样做的后果是极有可能被中间人攻击,会话的安全性得不到保障。如果有中间人对通信过程中的数据进行了嗅探和篡改,你的程序却会毫不知情。虽然在开发阶段由于条件限制不能正确配置证书,也不能忽略警告,也不能忽略证书校验。

高级程序员的写法

可以为 verify 传入 CA_BUNDLE 文件的路径,或者包含可信任 CA 证书文件的文件夹路径:

requests.get('https://github.com', verify='/path/to/certfile')  

也可以将其保持在会话中:

s = requests.Session()
s.verify = '/path/to/certfile' #如果 verify 设为文件夹路径,文件夹必须通过 OpenSSL 提供的 c_rehash 工具处理。

还可以通过 REQUESTS_CA_BUNDLE 环境变量定义可信任 CA 列表。