背景
经常会遇到抽奖活动根据登记的手机号发短信验证抽奖,或者公开的投票系统,又或者面向马路上的消费者展开调查问卷。这些场景下都有可能会有不法分子借此谋利或者恶意破坏。
防刷不能靠一门单一的技术,而是要综合分析可能的破解手段,评估攻击者愿意做到什么地步,以和黑产打一场全面战争的角度思考问题。即:如何以最小的消耗,来最大限度的浪费黑产的时间和金钱。
而这种问题必然是没有银弹的。所有只提出一种单一手段的答案都该被踩——“技术解决一切”对于某些场合,是一种过于幼稚的幻想,得让现实需求好好削几个耳光治一治。
从这个意义上,单纯的提问这个问题,信息量太少了。具体策略必然需要根据具体的场景而定。例如:
-
活动做多大规模?
-
活动有多大利益?
-
能否估计出可能的攻击者,会投入多大量级的资金?
-
预计投入多少资金用于防刷技术?
-
无论如何防刷,刷单损失客观上仍不可避免。那么最高可以容忍多少个百分点?
我们如何设计防刷系统,尽可能的规避此类问题的发生,本次就来探讨一下。
方案
刷接口行为一直以来都是个难题,无法从根本上防止。但是我们可以尽量减少刷接口带来的伤害,比如:通过人为增加的逻辑限制。
1、验证码:采用非常复杂的验证码
确切的说验证码的出现不是针对于人,而是针对于机器。通过复杂度和识别难易度的控制来阻拦掉一部分刷票机,从而减少刷票的发生。但随着软件技术、识别技术的发展越来越多的验证码面对着先进的刷票软件也失去了其防范的作用、但是专业刷票机可以攻破。如果不用验证码,投票基本就歇菜了,验证码获取方式,采用异步加载,即点击输入框时,才去请求,投票成功后,删除验证码的 Session。
2、限时投票
比如:从早8点至晚23 点
3、设置投票间隔
用户投票后,需要隔多长时间才能继续投。很多投票站点基本上都有这个限制,但是对于更改 IP的攻击,就没办法了
4、投票结果展示:延迟展示,友好展示
页面上投票,JS 立马加1,但是刷新页面,不一定立马展示最新投票结果,返回状态给页面(感谢您的投票!或者 投票成功!至于有没有成功,另说了!)
5、扣量逻辑:常见于一些软件评选之类的投票
这是个杀手锏,后台跑脚本实时监控异常增长(刷票)的项,然后实施扣量逻辑即对于这个项,投 10 票才算一票
6、Cookie:常用的手段。比较低级
投票后,在客户端写入 Cookie,下次投票时判断 Cookie 是否存在但是,这种方式非常容易攻破,因为 Cookie 可删除
7、加密选项 ID:对一些投票选项的ID,进行随机加密
加密算法,加Salt,并且设置有效时间,比如5分钟内服务器端进行解密并且验证
8、nginx限制链接数
ngx_http_limit_conn_module
ngx_http_limit_req_module
nginx_limit_speed_module
可以使用这三个模块来限制,不过这不是一个好的解决方法
9、iptables限制
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j DROP
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --set -j ACCEPT
/sbin/iptables -t filter -A INPUT -p tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 10 --connlimit-mask
32 -j REJECT
具体脚本
#!/bin/bash
# Date: 2015-09-29
# # Author: cpz@erongtu.com
shopt -s -o nounset
export PATH=/usr/bin/:/bin
iptables_log="/tmp/iptables_conf.log"
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j DROP
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --set -j ACCEPT
/sbin/iptables -t filter -A INPUT -p tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT
while [ true ]; do
#sleep 1
for IP in `netstat -an | grep -i ':80 '|grep 'ESTAB' | awk '{print $5}' | cut -d : -f 1 | sort | uniq -c | awk '{if($1 > 30 && $2!="127.0.0.1" ) {print $2}}'`
do
/sbin/iptables -L -n | grep $IP >/dev/null || /sbin/iptables -A INPUT -p tcp --dport 80 -s $IP -j DROP
echo "/sbin/iptables -A INPUT -p tcp -s $IP -j DROP" >> ${iptables_log}
done
done
本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。