工欲善其事,必先利其器。git
給本身定下寫文章的目標後,就去找了幾家博客平臺來發布文章;做爲一個懶人,不能全部博客文章都手動去各家平臺發佈,只好經過編寫腳原本發佈。可是除了Github
提供了比較詳細的Api
外,其餘國內的博客平臺都沒有提供對應的接口,但總有辦法的。github
下面是我對某家博客平臺模擬登陸流程的記錄(打死我都不會說這家平臺是S開頭的),我的以爲挺有意思的,也能從中學到很多產品安全設計的思路。ajax
Babel
chrome
Cheerio.js
segmentfault
SuperAgent
後端
Chrome 瀏覽器
api
注:工具只是實現結果的一個手段,並不必定須要掌握這些工具,只要知道它們是幹嗎的就好了。瀏覽器
先進入主頁找到用戶登陸頁,以下圖所示:安全
標準的登陸框,在這邊須要把Chrome
的控制檯打開,進入Network
頁,把 Preserve log (頁面跳轉也能記錄日誌,感謝 鐵臂狗 告知)的選項勾中, 以下圖所示:
抓包分析請求,先從輸入正確密碼開始:
我把暴露隱私的兩個地方打碼了(這兩塊也是咱們接下來要着重要分析的點)
能夠從中看到請求頭,咱們先把這些請求頭照抄下來
const base_headers = { Accept: '*/*', 'Accept-Encoding':'gzip, deflate', 'Accept-Language':'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2', 'Cache-Control':'no-cache', Connection:'keep-alive', DNT:1, Host:'segmentfault.com', Origin: 'http://segmentfault.com', Pragma:'no-cache', Referer: 'http://segmentfault.com/', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest' }
咱們能夠看到在請求登陸的時候 Header 就已經帶有 Cookie 了,這在我日常的設計中沒有作過,因此我就試着把 Cookie 刪後再請求,看看有什麼效果。刪除 Cookie 的方法以下所示:
利用排除法不停刪除並繼續試着登陸,都能完成登陸;直到刪除 PHPSESSID 的時候發現刪除以後再登錄是會報錯的,因此這個 PHPSESSID 確定是有用的(沒用過PHP對這個不太瞭解),所以我判定這個 Cookie 是在後端做爲驗證登陸的一個字段;所以我能夠經過在登陸以前先下載首頁並拿到 Cookie,放到請求頭上作做爲模擬 Header。
import request from 'superagent' let cookie; req .get(urls.mainpage) .end((err, res) => { // 從上圖能夠看到咱們須要的cookie是PHPSESSID開頭的 cookie = res.headers['set-cookie'] .join(',').match(/(PHPSESSID=.+?);/)[1] })
本覺得拿到 Cookie 以後就能夠開開心心的作登陸請求,然而這麼簡單的話這篇文章頁也就沒什麼寫的必要了。
繼續分析請求 HTTP 包,能夠發如今每次請求的時候,url 後面老是會帶一個 queryString(圖 2),我在這裏耗費了很多時間,毫無頭緒,只能追進源碼裏面摸索。
找到上圖中的源碼,能夠看到這個源碼是被壓縮過的,不要着急,chrome 提供了 formatt 功能,點擊最下面的{}
,能夠對壓縮的代碼重排,至少是勉強能夠閱讀的代碼了。
接下來的事情就是怎麼從這堆代碼中抽絲剝繭找到對咱們有用的信息,但是這麼多的代碼一步步看下來也會看到頭暈腦脹,眼睛滴血。那麼就試試看能不能使用查找的方式從源碼中找到我須要的東西。使用快捷鍵 ctrl+F,鍵入 /login
(/login
是做爲登陸的連接的,感受上可能會有很大機率能搜到相關代碼)
很巧的是,搜到了相關的代碼。從中能夠看到此網站使用了 JQuery 的 Ajax 發送相關 HTTP 請求,那麼,url 即是 e.attr("action")
,從下面的 DOM 結構能看到 action 是api/user/login
。
仍是沒有找到 queryString, 那就換個關鍵詞試試看,此次搜索 _=
(看圖2,queryString 是由_=
拼接起來的)
從上圖能夠看到有7個結果,而被黃色標註出來的那行纔是咱們想要的。JQ 的 ajaxSend 能夠在 Ajax 發送以前作一些處理。從上圖能夠看出,請求的時候在 url 的後面增長一個 n._
,那就繼續去找n._是什麼?因爲截圖截少了,我就再也不從新截圖,從上圖的第一行能夠看到 _ 是window.SF.token,由此咱們就摸到 token 的 G 點,整個流程明朗了許多。接下來全局搜索 window.SF.token,沒找到。我知道 window 是全局變量,爲何把 token 放到 window 上?能夠想多的是 token 並無在當前的 script 標籤內。接下來去 index.html 內查找:
找到了!能夠看到 token 是被包裹在一個獨立的 script 標籤內,在後端生成HTML模板的時候就已經插入。
找到 token 以後就很簡單了,拿到這個字符串表達式,運行,拿到token。
原理我以前寫過一篇文章,移步
import cheerio from 'cheerio' import request from 'superagent' let cookie; // 爲何這樣作 function getToken(s) { let $ = cheerio.load(s) , text = $('body script').eq(2).text() , fn = new Function('window', text + ';return window.SF.token') , token = fn({}) $ = null return token } req .get(urls.mainpage) .end((err, res) => { let token = getToken(res.text) // 從上圖能夠看到咱們須要的cookie是PHPSESSID開頭的 cookie = res.headers['set-cookie'] .join(',') .match(/(PHPSESSID=.+?);/)[1] })
拿到 token 和 Cookie ,抓包分析所須要的登陸字段:
{ mail: 'xxxxx@xx.xx', // 郵箱 password: 'xxxxxxx', // 密碼 remember: '1' // 是否記住登陸 }
登陸:
req .get(urls.mainpage) .end((err, res) => { let token = getToken(res.text) // 從上圖能夠看到咱們須要的cookie是PHPSESSID開頭的 cookie = res.headers['set-cookie'].join(',') .match(/(PHPSESSID=.+?);/)[1] req .post(urls.login) .query({'_': token}) .set(base_headers) .set('Cookie', cookie) .type('form') .send(conf) .redirects(0) .end((err, res) => { console.log(res) }) }) })
世上無難事只怕有心人
登陸是最基礎也最核心的功能,經過對登陸流程的分析,基本弄清楚了此博客平臺的驗證機制,在分析的過程當中鬥智鬥勇,利用本身掌握的知識一步一步破解謎題的自己就是一件頗有意思的事情,之後也能夠將此方法用到本身的登陸流程設計中。
登陸以後能施展的手段就不少了: 提問題,發表文章,建立標籤等等,用到得知識都在上面說過了,按下不表。
有須要源碼的同窗,歡迎 Star