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 入门