年会抽奖程序的一些总结

起源

2019年年会的到来,当然免不了激动人心的抽奖环节啦,那直接延用上一年的抽奖程序吧,然而Boss希望今年的抽奖程序能够能让所有人都参与进来,一起来抢有限奖品,先到先得,而不是站在那里盯着屏幕。

OK,程序内容大概是这样子,每个人在手机浏览器打开抽奖程序界面,系统会随机给个数字,谁戳屏幕上的圆形最快最准,就能参与抽奖活动,有多少奖品就有多少场battle(仅限手机浏览器打开 & 每人仅限获得一个奖品

重要的是,年会之前得把程序公布出来,让其他同事想办法作弊,硬件作弊软件作弊都允许,我们主要分析软件作弊并制定对应防御策略,就像是一场CTF,对方是攻击,我们是防御。

本文有引用他人文章,若有侵权或其它不当,会立即删除。

开发过程

我跟另一个同事完成这个项目,他负责后端,我负责前端,整体采用React+Nodejs+Express+MySQL的架构,这个项目有实时的需求,因此我们用到了socket.io

首先,我们分析了对方作弊的可能:

  1. 通过抓包分析,成功伪造点击请求
  2. 找到圆形位置,实现高准确率的点击
  3. 搞垮其他竞赛者的账号,自己稳步前进
  4. 直接搞掉服务器,修改数据库

对于作弊3,账号列表是年会抽奖前10分钟公布的,所以作弊者没有充足的准备时间。

对于作弊4,都是自己人,应该不会那么狠吧...

那么,我们主要针对作弊1作弊2做了以下防御:

后端防御

  • 校验请求参数是否有效
  • 分析正确点击频率,超过正常点击阀值则作惩罚处理
  • 点击错误次数过多则作惩罚处理

前端防御

  • 使用webpack-obfuscator混淆打包js代码,加大代码分析难度
  • react-konva画圆形,防止对手轻易获取DOM节点并执行点击事件
  • 圆形的颜色和位置随机,防按键精灵之类的软件
  • 核心websocket请求采用白盒加密
  • 普通请求采用rsa+aes混合加解密

经过了一个星期的开发和防御策略研究,我们把程序弄出来了,等待年会的到来。

抽奖过程

年会抽奖那天,在大屏幕上面可以看到每个人的点击数,注意到有个同事的按击次数值飚得极快,很明显他作弊成功了,但我想不明白是怎么做到的。于是年会结束后我向他请教,才得知作弊手法。

结果分析

作弊手法如下,非常简单,在手机浏览器的地址栏输入下面一段代码,回车即可执行。跟我一样不知道浏览器地址栏可以执行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‘);

Reference

socket.io

白盒加密

webpack-obfuscator

JavaScript根据种子生成随机数实现方法

浏览器地址栏运行JavaScript代码

在 Chrome DevTools 中调试 JavaScript 入门

原文地址:https://www.cnblogs.com/DTBelieve/p/10323673.html

时间: 2024-10-12 05:47:50

年会抽奖程序的一些总结的相关文章

十分简单的年会抽奖程序

年会那个抽奖程序崩溃实在令人印象太深刻了,所以自己弄了一个简单版本的... data=[] #从数据库或者文件获取员工抽奖id,放到data iNum= raw_input("please input the numbers:\n")#抽几个人 # method= raw_input("please input the method:\n")#做所谓奇偶数抽奖,没意义 allwindata=[] while iNum: windata=[] for i in ran

javascript实现抽奖程序

昨天开年会的时候看到一个段子说唯品会年会抽奖,结果大奖都被写抽奖程序的部门得了,CTO现场review代码. 简单想了一下抽奖程序的实现,花了十几分钟写了一下,主要用到的知识有数组添加删除,以及ES5 数组新增的indexOf,filter方法, 为了刷新页面后仍能保存已中奖记录,用了localStorage存盘. 刚开始是用随机数直接取编号,发现要剔除已中奖的人很麻烦,如果重复要递归调用,如果中奖的人太多到最后随机数取到已中奖的人概率太大,所以换用两个数组实现,一个记录已中奖的号码,一个记录未

关于年会抽奖那些事

http://blog.chinaunix.net/uid-11121450-id-3480134.html快春节了,各个公司都陆续举办年会,ipad作为年会抽奖的大奖都卖脱销了,在年会抽奖出现尴尬的是:抽奖抽多了,没有奖品可发. 我昨天总结了在开发过程中遇到的抽奖问题 1.抽奖类型 1.1 即开型 提交后立即知道是否中奖:大转盘,老hu机 1.2 公证型 由公证处公证,现场抽奖 1.3投票型 根据投票数最高排名,选出中奖者 1.4 评选型 由客户根据作品质量选取 这四种类型中出现错误时,最难处

jQuery实现圆盘活动抽奖程序效果

<script type="text/javascript" src="jquery-1.7.2.min.js"></script> <script type="text/javascript" src="jQueryRotate.2.2.js"></script> <script type="text/javascript" src="jqu

java模拟一个抽奖程序

今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文本框 JTextField * 按钮  JButton 还涉及到线程Thread 先看效果图: 但是这里留一个问题?就是去除重复数字(可以自己先实现,后期我会上传的) 下面看看代码,代码中有注释,不懂留言: package thread.test1; import java.awt.BorderLa

年会抽奖

小游戏,年会抽奖,都很期待的. <body> <div id="button"> <input id="B1" onclick="Begin()" name="B1" type="button" value="开始" /> <input id="B2" onclick="Stop()" name="

使用jQuery+PHP+Mysql实现抽奖程序

抽奖程序在实际生活中广泛运用,由于应用场景不同抽奖的方式也是多种多样的.本文将采用实例讲解如何利用jQuery+PHP+Mysql实现类似电视中常见的一个简单的抽奖程序. 查看演示 本例中的抽奖程序要实现从海量手机号码中一次随机抽取一个号码作为中奖号码,可以多次抽奖,被抽中的号码将不会被再次抽中.抽奖流程:点击“开始”按钮后,程序获取号码信息,滚动显示号码,当点击“停止”按钮后,号码停止滚动,这时显示的号码即为中奖号码,可以点击“开始”按钮继续抽奖. HTML <div id="roll&

相同概率的抽奖程序另类实现——使用数据库,无需数学原理

抽奖,是很多企业.聚会的常见玩乐形式,光彩绚丽的抽奖屏幕背后,是计算程序+抽奖用户信息.程序=算法+数据结构. 好,说抽奖程序的的实现吧.这个实现一般需要应用数学原理.而本文的方法是我在参加一次婚礼的抽奖体验后突然想到的,一种比较简单.无需数学原理的方法. 功能:能按照相同概率,从用户集合中抽出随机的部分用户集合作为中奖者.抽奖可以进行多次,对已中奖的用户不会重复抽取. 使用技术: 1.SqlServer数据库,使用NewID()作为select随机筛选函数 2.sql随机函数 3.为了快速方便

JavaScript简单抽奖程序的实现及代码

JavaScript简单抽奖程序的实现及代码 1.需求说明 某公司年终抽奖,需要有如下功能 1)可以根据实际情况设置到场人数的最大值 2) 点击"开始",大屏幕滚动,点击"停止",获奖者的编号出现在大屏幕上 3)在界面里显示全部奖项获奖人编号 4)不重复获奖 5)不会因为输入错误而导致抽奖结果异常. 2.代码呈上 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">