2019年年會的到來,固然免不了激動人心的抽獎環節啦,那直接延用上一年的抽獎程序吧,然而Boss但願今年的抽獎程序可以能讓全部人都參與進來,一塊兒來搶有限獎品,先到先得,而不是站在那裏盯着屏幕。javascript
OK,程序內容大概是這樣子,每一個人在手機瀏覽器打開抽獎程序界面,系統會隨機給個數字,誰戳屏幕上的圓形最快最準,就能參與抽獎活動,有多少獎品就有多少場battle(僅限手機瀏覽器打開 & 每人僅限得到一個獎品
)html
重要的是,年會以前得把程序公佈出來,讓其餘同事想辦法做弊,硬件做弊
和軟件做弊
都容許,咱們主要分析軟件做弊
並制定對應防護策略,就像是一場CTF,對方是攻擊,咱們是防護。前端
本文有引用他人文章,如有侵權或其它不當,會當即刪除。java
我跟另外一個同事完成這個項目,他負責後端,我負責前端,總體採用React+Nodejs+Express+MySQL的架構,這個項目有實時的需求,所以咱們用到了socket.ioreact
首先,咱們分析了對方做弊的可能:webpack
對於做弊3
,帳號列表是年會抽獎前10分鐘公佈的,因此做弊者沒有充足的準備時間。
對於做弊4
,都是本身人,應該不會那麼狠吧...git
那麼,咱們主要針對做弊1
和做弊2
作了如下防護:
後端防護github
前端防護web
通過了一個星期的開發和防護策略研究,咱們把程序弄出來了,等待年會的到來。
算法
年會抽獎那天,在大屏幕上面能夠看到每一個人的點擊數,注意到有個同事的按擊次數值飈得極快,很明顯他做弊成功了,但我想不明白是怎麼作到的。因而年會結束後我向他請教,才得知做弊手法。
做弊手法以下,很是簡單,在手機瀏覽器的地址欄輸入下面一段代碼,回車便可執行。跟我同樣不知道瀏覽器地址欄能夠執行js代碼的童鞋,請看這篇文章瀏覽器地址欄運行JavaScript代碼
javascript:Math.random=function(){return 1;}
因爲我在圓形隨機位置和隨機顏色的設置上用到了Math.random這個方法,此時,他的按擊圓形就定死在同一個位置,衆人皆動我獨靜,並且都是正常點擊請求,必須贏呀!
// 修改前 function getRandomNumber(min, max) { const range = max - min; const random = Math.random(); const num = min + range * random; return num; }
找到問題所在,很明顯我須要找個隨機函數方法替換Math.random
,因而我google了幾篇文章,都提到線性同餘生成器(LCG, Linear Congruential Generator),貌似全部運行庫都是採用這種算法生成僞隨機數,我就把getRandomNumber
函數改爲下面的模樣,問題獲得了暫時的解決。
// 修改後 const getRandomNumber = (function() { let seed = Date.now(); function random() { //線性同餘生成器(LCG, Linear Congruential Generator) seed = (seed * 9301 + 49297) % 233280; return seed / (233280.0); }; return function rand(min,max) { const range = max - min; const random_num = random(); const num = min + range * random_num; return num; }; })();
可是,getRandomNumber
的代碼功能仍是很是容易改,畢竟混淆過的js依舊是裸奔着的,這一點是避免不了的。
好比說,咱們都知道知乎能夠設置文章的權限,例如禁止轉載之類的,有一次我看到這篇知乎文章應對流量劫持,前端能作哪些工做?,想複製代碼下來運行下卻被告知禁止轉載
,打開chrome控制檯查看代碼塊內容,惋惜代碼內容變成富文本內容形式,因而我另尋法子,直接在js上面修改。
首先,定位到複製功能觸發的文件和代碼段。
第二步,在控制檯Sources->Overrides下,打勾Enable Local Overrides
第三步,在控制檯下面Sources->Page下,找到剛剛定位到的代碼文件,右鍵Save for overrides
第四步,直接把handleCopy
的處理邏輯註釋掉,在控制檯的Overrides下直接修改,或者在選定保存的本地文件夾中修改。
最後,保存修改後的代碼,刷新頁面,便可複製成功。
var SriPlugin = require('webpack-subresource-integrity'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ScriptExtInlineHtmlWebpackPlugin = require('script-ext-inline-html-webpack-plugin'); var ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin'); var path = require('path'); var WebpackAssetsManifest = require('webpack-assets-manifest'); var writeJson = require('write-json');
socket.io
白盒加密
webpack-obfuscator
JavaScript根據種子生成隨機數實現方法
瀏覽器地址欄運行JavaScript代碼
在 Chrome DevTools 中調試 JavaScript 入門