現階段,在微信朋友圈舉辦的投票活動層出不窮,相信已經有不少同學對此不勝其煩,因為總會時不時地冒出個人(親戚、朋友、or whatever)來請你幫TA投票。
本文倒沒有打算從道德或情感層面來探討這個問題,我所感興趣的是,當前大多數投票活動其實都是存在明顯漏洞的,透過簡單的技術手段就可以實現「刷票」。
這裡就有一個案例。
某美髮網路商城(以下簡稱S商城)在微信平台上舉辦了一場線上投票活動,微信用戶可透過活動連結造訪投票頁面,對喜歡的髮型師作品進行投票;每個微信帳號每天只能給單一作品投1張選票。
投票活動頁面如下圖所示:
表面上看,S商城已經對投票活動進行了反作弊處理,因為限制了每個微信用戶每天只能投一張票。如果使用者都是正常地透過微信存取這個投票服務進行投票的話,的確是能起到預期效果的。
然而,如果查看投票頁面的原始地址,即按住頁面向下拖動,會發現屏幕頂端顯示為"本網頁由XXX提供",需要注意的是,這裡的"XXX"並不是"mp.weixin. qq.com",而是S商城的網域。也就是說,這個投票活動的程式是運行在S商城的伺服器上面的。
基於上述分析,可以推斷出使用者投票操作的網路拓樸結構示意圖應該是這樣的:
當微信使用者造訪投票頁面時,微信伺服器只是進行了請求轉發,具體的投票計數與校驗都是在S商城的伺服器上的。
那麼,S商城是怎麼來區分投票用戶的呢?
這裡就牽涉到微信公眾平台OpenID
的概念了。官方對OpenID
的解釋是:加密後的微訊號,每個使用者對每個公眾號碼的OpenID是唯一的。
要驗證這一點也很容易,只需要透過採用多個微信帳號進行投票,並對投票過程進行網路抓包,查看POST中的參數就可以證實。
基於這一點,微信公眾平台在轉發投票請求時,會在POST參數中包含用戶的OpenID
;S商城在接收到投票的POST請求後,透過查詢當前OpenID
是否在當天已經投過票,就可以阻止單一用戶重複投票的行為了。
然而,這裡面卻存在著一個很大的漏洞!
S商城只能判斷OpenID
是否出現了重複,但是卻無法校驗OpenID
的有效性,因為它是無法呼叫微信伺服器來對這個OpenID
進行校驗的。
明確了這個漏洞後,要實現刷票就很簡單了。
OpenID
參數,重複進行POST請求。如果要實現批量刷票,或刷票自動化操作,那麼就可以將刷票請求透過Python腳本來實現;甚至,採用LoadRunner也是可以的。
運行VoteRobot.py
,輸出日誌如下:
======== Start to vote zpid(38), Total votes: 3
1 tickets has been voted, the next ticket will be voted after 35 seconds.
2 tickets has been voted, the next ticket will be voted after 31 seconds.
3 tickets has been voted, the next ticket will be voted after 10 seconds.
======== Voting Ended!
需要注意的是,通常自動化刷票時最好有個隨機的時間間隔,並且,最好能動態模擬不同的設備,即修改User-Agent
,否則,服務端可以較為容易地識別作弊行為。
看到這裡,也許有的同學心中竊喜,以後投票都可以採用這種方式「刷票」了麼?
很遺憾,當然不是。
其實本文案例的漏洞是很低級的,只是,目前的確還存在不少比例的投票活動是採用這種模式。
要判斷一個投票活動是否可以用這種方式來作弊也很簡單。採用本文中的方法,若查看到活動的網址是非微信官方的,而且整個投票過程也沒有額外的校驗,那麼實現作弊的可能性就很大了;再透過抓包看下通訊交互過程,並用網路請求工具修改參數後重新請求下,即可驗證是否真的可以作弊了。
另外,也許有人想問了,網路中的投票活動就沒法杜絕「刷票」行為了麼?
答案是,完全杜絕的確很難。聽過12306的黃牛黨沒?聽過Apple Store專業給應用程式刷榜的沒?聽過「網路水軍」、「五毛黨」沒?
不過,活動舉辦方可以透過一些手段,大幅提高作弊的門檻。例如,目前有不少活動就採用如下方式:
不管採用這兩種方式中的哪一種,本文中的「刷票」方法就完全失效了。