此文起因
有園友私信我探討關於博客園模擬登錄的事,年前也玩了一段時間的 node(詳情可以參考我的 node 項目集 https://github.com/hanzichi/funny-node 厚着臉皮求 star),做之前想的可能只是一次簡單的 post,嘗試下來完成后還是有了不少收獲。為了能讓后人有個參考,遂成此文。
登錄抓包
閑話少說,既然是模擬登錄,我們來看看登錄過程都發生了什么。
打開登錄頁面(http://passport.cnblogs.com/user/signin?ReturnUrl=http://passport.cnblogs.com/),填入用戶名和密碼,點擊登錄后,我們很容易地抓到了登錄包。
先看返回頭:
后續的實踐中,我用回帖操作來證明已經完成登錄。抓取回帖的包,發現回帖操作需要攜帶一個 key 為 .CNBlogsCookie 的 cookie 識別身份。又發現,只要一次登錄后將瀏覽器中的該 cookie 取出,就能模擬該用戶了。我將客戶端的 key 為 .CNBlogsCookie 的 cookie 取出,寫下如下代碼:
superagent
.post('http://www.cnblogs.com/mvc/PostComment/Add.aspx')
.set("Cookie", ".CNBlogsCookie=yourCookieValue")
.send({"blogApp": "xxx"})
.send({"body": "test"})
.send({"postId": xxx})
.end(function (err, sres) { // callback
});
居然能回帖,完全不用管其他操作了。不明原因,但是細思極恐,如果你被人盜取了該 cookie,后果你懂的。
要手動從瀏覽器中復制獲取該 cookie 顯得有點 low,如何能自動獲取該 cookie 值?
再看請求頭:
實踐發現,有四個值是必須模擬的(已標出),而且全都照抄即可。
最后看 post 的數據:
這是什么玩意?原來是加密后的用戶名以及密碼數據。接下去簡單了解下加密方式(盡管模擬登錄並不強依賴於此)。
jsencrypt
博客園的加密方式為 RSA,依賴 jsencrypt 這個庫。
這里不詳述 RSA 加密方式,詳情可以參考阮一峰老師的文章:
jsencrypt 加密是可逆的加密方式,客戶端用公鑰加密,服務端用私鑰解密,每次加密生成的字符串都不一樣,但是解密后都一樣。用明文發送賬戶名和密碼,如果該包被截獲,那么你的密碼也將大白於天下,存在着極大的安全隱患,但是客戶端用了 jsencrypt 加密,如果被截獲,截獲的也僅僅只是加密后的字符串,沒有私鑰解密的話,也無濟於事。我們 post 包中的 input1 和 input2 的數據正是在客戶端加密后的用戶名以及密碼。
打開 http://passport.cnblogs.com/user/signin?ReturnUrl=http://passport.cnblogs.com,ctrl+u 查看網頁源代碼,可以清楚看到 jsencrypt 加密的公鑰,賬戶名密碼的加密過程,以及用 ajax 方式登錄所需要的數據等。
參考 博客園加密登錄--jsencrypt 我寫了個簡單的基於 jsencrypt 的加密解密 demo https://github.com/hanzichi/funny-node/tree/master/cnblogs-auto-login/jsencrypt-demo。因為解密過程有用到 PHP 中的 openssl,所以記得在 php.ini 文件中打開 openssl,具體操作為找到 extension=php_openssl.dll
這一行,把注釋打開(將前面的封號去掉)。
另外,根據已經披露的文獻,目前被破解的最長 RSA 密鑰是 768 個二進制位。也就是說,長度超過 768 位的密鑰,還無法破解(至少沒人公開宣布)。因此可以認為,1024 位的 RSA 密鑰基本安全,2048 位的密鑰極其安全。Online RSA Key Generator 可以參考 http://travistidwell.com/jsencrypt/demo/index.html,我這也備份了一份 https://github.com/hanzichi/funny-node/tree/master/cnblogs-auto-login/key-generator。
編碼
進入最后編碼階段。
首先我們需要獲取加密后的賬戶名以及密碼,可以抓個包復制下參數,雖然每次加密后的字符串都不一樣,但是解密后的結果是一樣的,所以如果后期不主動修改用戶名和密碼,這樣做完全沒有問題。但是我覺得這樣做不優雅,能不能通過用戶名和密碼,獲取加密后的結果?嘗試着找了下 node 下的 RSA 模塊,無奈可能使用方式不大一樣,未果。於是換了個方式,客戶端進行加密,將加密后的數據存儲到服務端,供 node 調用。
然后就是模擬登錄了,VerificationToken 參數可以爬取頁面取,也可以直接拿個值賦值。登錄成功后保存 cookie 以便下次操作時調用。
詳細代碼和操作步驟已同步在 Github,歡迎交流探討。