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

  1. Raise sms.getIpMaxSendCount() in the SMS code properties if the limit is unrealistically low for shared-IP networks
  2. Delete the Redis ipSmsCountKey to reset the quota (testing only)
  3. If deployment sits behind an LB/proxy, ensure getRemoteAddr() reads X-Forwarded-For so counts are per real client, not per proxy IP
  4. 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

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)