簡述
最近在研究微信機器人的Python腳本,很是好奇它是如何做到的,后來發(fā)現(xiàn)它只是模擬登陸網(wǎng)頁版微信而實現(xiàn)的,通過研究這些東西也學(xué)到了不少東西,首先是腳本的里面都是通過簡單的HTTPS請求來實現(xiàn)的,既然是模擬網(wǎng)頁版微信,那一定是抓取網(wǎng)頁版微信的接口神得,以前一直以為HTTPS是不可抓取的,后來發(fā)現(xiàn)并非如此偷仿,通過《使用 Charles 獲取 https 的數(shù)據(jù)》一步步抓取了網(wǎng)站的接口,發(fā)現(xiàn)騰訊的安全措施也并非那么好哩簿,經(jīng)過解析都是明文的,瞬間感覺很不安全炎疆。那么HTTPS真的是這么不安全嗎卡骂,也不是,只不過是沒有使用SSL Pinning,如果是使用了SSL Pinning的HTTPS還是無法抓取的形入。
起因
了解了微信機器人的原理全跨,我就慢慢摸索著這個項目的具體實現(xiàn)細(xì)節(jié),我想直接使用Charles抓取這個項目究竟使用了哪些微信的接口亿遂,發(fā)現(xiàn)沒有成功浓若,給我拋了個下面的錯誤:
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)
猜想
我很是納悶,測試了自己的Charles抓取HTTPS也是正常的,那Charles的代理證書就沒問題蛇数,為什么Python還給拋出了這樣的一個錯誤,之后我將Charles關(guān)閉挪钓,項目正常運行,很是奇怪耳舅,我猜想肯定代理的問題碌上,畢竟Charles抓取的原理是作為一個代理來截獲的。
調(diào)試
于是我嘗試一步步調(diào)試浦徊,發(fā)現(xiàn)Python確實能識別出代理和真實請求馏予,于是我使用了下面去掉代理的代碼測試了一下:
r = requests.get(url='https://login.weixin.qq.com',proxies={'no_proxy':'login.weixin.qq.com'})
結(jié)果是成功的發(fā)送了請求,也沒有報錯盔性,天真的我以為可以確定就是代理的問題霞丧,其實也不盡然,這個請求Charles居然抓不到了冕香,欲哭無淚蛹尝,只好繼續(xù)一步步調(diào)試到底是哪里出了問題。
結(jié)果我發(fā)現(xiàn)了Python的如果發(fā)現(xiàn)是HTTPS請求悉尾,會默認(rèn)開啟證書驗證verify = True
,但是我的Charles代理證書也是沒問題的突那,為什么就通不過呢,真實的原因就在于构眯,Python對于HTTPS請求中的證書的驗證愕难,并不會去系統(tǒng)的證書系統(tǒng)(Mac的鑰匙串訪問)驗證,而是使用它自己的證書cacert.pem
,被Python放置和定義的路徑為DEFAULT_CA_BUNDLE_PATH = certs.where()
,其值是/Library/Python/2.7/site-packages/certifi/cacert.pem
,我們雙擊打開之后會發(fā)現(xiàn)他會安裝在了鑰匙串訪問
中,
其實在系統(tǒng)的根證書的列表里也有以
GlobalSign Root CA
命名的證書务漩,但其實兩個是不一樣的東西,我們可以用文本方式打開Python下的cacert.pem
證書,發(fā)現(xiàn)里面有很多證書頒發(fā)機構(gòu)也就是說如果你的HTTPS請求到的服務(wù)器證書的頒發(fā)機構(gòu)被包含在Python的證書下它褪,驗證就能通過饵骨,網(wǎng)頁版的微信的HTTPS服務(wù)器證書:
包含在
cacert.pem
證書里面,那自然是可以通過請求茫打,而Charles的自簽名證書居触,是沒有在cacert.pem
證書里,驗證就不會通過老赤。
驗證
你還記得你買票的時候轮洋,12306會提示你安裝一個證書嗎,畢竟這不是一個在CA付費機構(gòu)購買且讓瀏覽器信任的證書,這是一個自簽名證書的網(wǎng)站抬旺,我們可以通過12306
網(wǎng)站證明一下證書的問題:
r = requests.get(url='https://kyfw.12306.cn/otn/')
正如預(yù)想的那樣弊予,Python拋出了certificate verify failed
的錯誤。
參考