短信接口防刷,主要通过两个方面来实现:一个是短信接口加签和时间戳;另外针对短信接口,增加防刷 check 机制;
具体如下:
一、针对短信接口加签和时间戳
加签配置很简单,直接将需要控制的接口加到 yml 的参数 jeecg.signUrls 中即可。
目前涉及接口:
/sys/sms /sys/sendChangePwdSms
二、短信接口增加高频校验
同一个 IP 一分钟发送超过 5 次短信,则获取短信接口提示需要验证码
防止刷短信 check 具体逻辑:
- 同一 IP,一分钟内发短信不允许超过 5 次(每一分钟重置每个 IP 请求次数)
- 同一 IP,一分钟内发短信超过 20 次,进入黑名单,不让使用短信接口
2.1 在发送短信的地方,增加高频 check
2.2 获取短信的验证码接口
2.3 防止刷短信工具类实现如下
package org.jeecg.common.util; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ConcurrentHashMap; /** * 防止刷短信工具 * * 1、同一IP,1分钟内发短信不允许超过5次(每一分钟重置每个IP请求次数) * 2、同一IP,1分钟内发短信超过20次,进入黑名单,不让使用短信接口 */ @Slf4j public class DySmsLimit { // 1分钟内最大发短信数量(单一IP) private static final int MAX_MESSAGE_PER_MINUTE = 5; // 1分钟 private static final int MILLIS_PER_MINUTE = 60000; // 一分钟内报警线最大短信数量,超了进黑名单(单一IP) private static final int MAX_TOTAL_MESSAGE_PER_MINUTE = 20; private static ConcurrentHashMap<String, Long> ipLastRequestTime = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, Integer> ipRequestCount = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, Boolean> ipBlacklist = new ConcurrentHashMap<>(); /** * @param ip 请求发短信的IP地址 * @return */ public static boolean canSendSms(String ip) { long currentTime = System.currentTimeMillis(); long lastRequestTime = ipLastRequestTime.getOrDefault(ip, 0L); int requestCount = ipRequestCount.getOrDefault(ip, 0); log.info("IP:{}, Msg requestCount:{} ", ip, requestCount); if (ipBlacklist.getOrDefault(ip, false)) { // 如果IP在黑名单中,则禁止发送短信 log.error("IP:{}, 进入黑名单,禁止发送请求短信!", ip); return false; } if (currentTime - lastRequestTime >= MILLIS_PER_MINUTE) { // 如果距离上次请求已经超过一分钟,则重置计数 ipRequestCount.put(ip, 1); ipLastRequestTime.put(ip, currentTime); return true; } else { // 如果距离上次请求不到一分钟 ipRequestCount.put(ip, requestCount + 1); if (requestCount < MAX_MESSAGE_PER_MINUTE) { // 如果请求次数小于5次,允许发送短信 return true; } else if (requestCount >= MAX_TOTAL_MESSAGE_PER_MINUTE) { // 如果请求次数超过报警线短信数量,将IP加入黑名单 ipBlacklist.put(ip, true); return false; } else { log.error("IP:{}, 1分钟内请求短信超过5次,请稍后重试!", ip); return false; } } } /** * 图片二维码验证成功之后清空数量 * * @param ip IP地址 */ public static void clearSendSmsCount(String ip) { long currentTime = System.currentTimeMillis(); ipRequestCount.put(ip, 0); ipLastRequestTime.put(ip, currentTime); } }