paascloud/paascloud-master · warning · ValidateCodeException
IP当天短信发送数上限
Error message
IP当天短信发送数上限
What it means
checkSendSmsCount also enforces a per-source-IP daily SMS quota: it reads ipSmsCountKey from Redis and throws ValidateCodeException('IP当天短信发送数上限') when the count exceeds sms.getIpMaxSendCount(). This blocks a single client IP from requesting too many SMS codes in one day, defending against bulk abuse where attackers rotate phone numbers but share an IP.
Solutions
- Raise sms.getIpMaxSendCount() in the SMS code properties if the limit is unrealistically low for shared-IP networks
- Delete the Redis ipSmsCountKey to reset the quota (testing only)
- If deployment sits behind an LB/proxy, ensure getRemoteAddr() reads X-Forwarded-For so counts are per real client, not per proxy IP
- Surface a clear message to the user ('too many requests from your network') when catching ValidateCodeException
Example fix
// before: proxy IP counted, all users share one quota
String remoteAddr = request.getRemoteAddr();
// after: resolve real client IP behind reverse proxy
String remoteAddr = request.getHeader("X-Forwarded-For");
if (PublicUtil.isNotEmpty(remoteAddr)) {
remoteAddr = remoteAddr.split(",")[0].trim();
} Defensive patterns
Strategy: try-catch
Validate before calling
Integer ipCount = (Integer) redisTemplate.opsForValue().get(ipSmsCountKey);
if (ipCount != null && ipCount > maxIpSendCount) {
throw new BizException("SMS daily limit reached for your network");
} Try / catch
try {
smsCodeSender.send(mobile);
} catch (ValidateCodeException e) {
log.warn("IP SMS quota hit: {}", e.getMessage());
return Result.error(429, "当前网络请求过于频繁,请稍后再试");
} Prevention
- Behind a load balancer, make sure the real client IP (X-Forwarded-For) is used so shared proxy IPs don't pool quota
- Set ipMaxSendCount high enough for CGNAT/office networks where many users share one IP
- Monitor ipSmsCount keys for abnormal growth indicating scraping or abuse
- Combine with the per-mobile limit so a single abuser is stopped earlier by the tighter quota
When it happens
Trigger: SMS code requests (send -> checkSendSmsCount) originating from one IP address whose Redis day-counter exceeds smsProperties.getIpMaxSendCount(); the counter is incremented on each send and kept for 1 day.
Common situations: Office/CGNAT networks where many users share one public IP and collectively exhaust the IP quota; load/perf testing from a single machine; ipMaxSendCount configured too low; users behind proxies or corporate NAT hitting the cap.
Related errors
AI-assisted analysis of paascloud/paascloud-master@781281a950 (2026-09-10).
Data as JSON: /api/errors/0a82a17eafa342e4.
Report an issue: GitHub.
Appendix: source
Thrown at paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java:123
Integer sendSmsRateCount = (Integer) redisTemplate.opsForValue().get(sendSmsRateKey);
if (sendSmsRateCount != null) {
log.error("操作频率过快 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("操作频率过快");
} else {
redisTemplate.opsForValue().set(sendSmsRateKey, 1, 1, TimeUnit.MINUTES);
}
Integer mobileSmsCount = (Integer) redisTemplate.opsForValue().get(mobileSmsCountKey);
if (mobileSmsCount != null && mobileSmsCount > sms.getMobileMaxSendCount()) {
log.error("Mobile当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("Mobile当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(mobileSmsCountKey, mobileSmsCount == null ? 1 : mobileSmsCount + 1, 1, TimeUnit.DAYS);
}
Integer ipSmsCount = (Integer) redisTemplate.opsForValue().get(ipSmsCountKey);
if (ipSmsCount != null && ipSmsCount > sms.getIpMaxSendCount()) {
log.error("IP当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("IP当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(ipSmsCountKey, ipSmsCount == null ? 1 : ipSmsCount + 1, 1, TimeUnit.DAYS);
}
Integer totalSmsCount = (Integer) redisTemplate.opsForValue().get(totalSmsCountKey);
if (totalSmsCount != null && totalSmsCount > sms.getTotalMaxSendCount()) {
log.error("当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(totalSmsCountKey, totalSmsCount == null ? 1 : totalSmsCount + 1, 1, TimeUnit.DAYS);
}
}
private String getRemoteAddr(HttpServletRequest request) {
String ipAddress = request.getHeader(X_FORWARDED_FOR);
if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader(PROXY_CLIENT_IP);
}
if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {View on GitHub (pinned to 781281a950)