最近客户发给我一个投票系统维护,说是系统老是容易出现502或者访问很慢的情况,一个接口请求需要25秒+。随之看代码:
前提:该项目是基于微信公众号网页端的投票系统,故可以获取到openid,每个用户限制每天投票最大10票。
1.原投票接口代码,参数为openid和作品id,后端不校验openid真实性,所以刷票可以伪造任意的openid请求接口。且每次投票都会查询投票记录是否超过十次,而记录表数据没有主键id,没有索引,数据量大,查询非常慢,故加redis存储每个openid当日投票次数,过期时回写到mysql。
开始想的比较简单,只要校验一下openid的真实性,调用了微信提供的接口:
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
根据openid获取用户信息校验是否真实微信用户。问题解决发布。
但是不到半天发现接口报错,查找原因发现微信接口返回
{"errcode":45009,"errmsg":"api freq out of limit"}
接口调用上限。随之更换方法。
2.前端授权后可以拿到openid,那么就让前端传过来保存,投票时查询是否存在。
修改发布后,还是有大量的刷票行为且openid均为真实微信用户。
继续加限制。
3.ip限制
投票接口加单ip请求限制。springboot下参考https://blog.csdn.net/a2986467829/article/details/125417858
加了限制后,效果还是不太理想,推断刷票使用了动态ip代理。
4.短信验证码
在用户点击投票时让用户填写手机号获取验证码校验,将记录存入redis,用户投票时校验该用户openid是否获取过验证码,如果获取过就让投票,反之不能。
目前暂时运行正常,没有出现访问慢及502的情况。
在此期间请教了许多人,给出的方法也都无外乎是这几种。其实做到这样真正意义上也还是防止不了刷票行为,只是过滤了大多低端的刷票。