1. 程式人生 > >【小鎮的技術天梯】刷票與防刷票的思考

【小鎮的技術天梯】刷票與防刷票的思考

【小鎮最近做的感動南通的投票活動目前有大概40w左右的投票記錄,小鎮通過篩選和排查,發現3000多條有刷票嫌疑的記錄,雖然說這些記錄對於總的投票活動來說基本上是九牛一毛,但是這觸及了程式猿的底線,你能刷票,就證明我的程式碼有問題,小鎮必須排查和完善】

【雖然說通過驗證碼機制可以很好的防止刷票,但是如果有了驗證碼,誰還願意投票?本來點一下就可以投票的事情硬要輸入無聊的4個字元實乃是丟失參與度的最好方法哈哈,因為有微信網頁授權的驗證機制,所以刷票不是非常容易就能實現的。小鎮這次來自己模仿一下如何刷票和反刷票。】

1、小鎮來刷票!

首先開啟投票的網頁,咱可以看到下方的我要投票按鈕,點開瀏覽器的F12檢視該按鈕的程式碼,如下圖所示:


【在這裡,我們可以看到“我要投票”按鈕的id是woyaotoupiao,那麼就在js的檔案中查詢關於woyaotoupiao這個id的相關點選事件,好,我們在下面找到了相應的程式碼,如下圖所示:】


我們可以看到事件中是按鈕的點選事件向toupiaoPHP.php檔案傳送了非同步的post請求,其中的引數攜帶了uid,openid,和selfopenid。

【明眼人一眼就看到了刷票的希望,對啊,反正只要向這個php檔案傳送post請求就可以刷票了,至於toupiaoPHP.php檔案裡面的驗證機制咱可以慢慢猜,但是隻通過這三個引數的可偽造性和不固定性就可以隨便刷啦!!】

這個發POST請求的不用小鎮教了吧。。基礎中的基礎,用php中的curl函式。然後攜帶引數就行啦,反正給個示例程式碼大家看看就行啦。

這裡我們定義個要傳送的陣列對吧。

$post_array=("openid"=>"xxxx","selfopenid"=>"xxxx","uid"=>"xxxx");

然後定義一個curl的例項,恩,再加上一些引數對吧。好了,$url就是那個toupiaoPHP.php檔案的地址就行了,然後就傳送

  1.     $options = array(  
  2.         CURLOPT_RETURNTRANSFER => true,
  3.         CURLOPT_HEADER         => false,  
  4.         CURLOPT_POST           => true,  
  5.         CURLOPT_POSTFIELDS     => $post_array,  
  6.     );  
  7.     $ch = curl_init($url);  
  8.     curl_setopt_array($ch$options);  

【然而,傳送出去以後,回來的卻是禁止刷票四個大字!!為啥呢,哦,變數的情況是可以排除的,為啥呢,變數的情況是合法且合理的,那麼只有一種可能嘍,應該是裡面有著referer的判定,如下圖所示,我們再給curl的引數裡面加上相應的referer引數。】

curl_setopt ($ch,CURLOPT_REFERER,'xxxxxxx');

然後再發送請求,好了,返回過來投票成功。然後去看看投票的情況確實漲了一點投票。

【沒錯,這就是不用驗證碼的後果,其實,在這種情況下,不用驗證碼是很難很難防止刷票爬蟲啊之類的,但是,這是微信投票,微信有個值openid是確定且固定的,通過這個引數我們可以來防止刷票,像剛剛的情況我們可以偽造openid,但是如果一定要通過該投票頁面給toupiaoPHP.php傳送post請求的話,那麼這個openid就是無法偽造的!因為每次投票頁面都是實時獲取openid的。正是因為這個原因,在toupiaoPHP的檔案裡面才會加入了referer的判定,確定post的請求是來自於投票頁面而不是隨便那臺伺服器上面的請求,然而,referer也是可以偽造的哎!!真是蛋疼。】

【好了,怎麼解決呢!!就圍繞著開啟投票頁面openid唯一確定性的定理來思考(暫且稱為定理吧,哎嘿嘿),我們可以在投票頁面的php中隨即一個10位以上的字串,並以openid為鍵,該字串為鍵值存入Redis(不需要持久化的資訊存redis最好了),然後post請求加一個引數,就是該隨即字串,最後toupiaoPHP檔案中在redis中檢視該openid的鍵值,如果和傳送的字串是一樣的,就代表該投票有效。】

【結束了,想法還是很簡單的,但是損失了點效能。思考的過程不難,抓住什麼東西是確定不能偽造的特點來進行就可以了。】