看一名Java开发人员以红队思维五分钟审计一套代码(4)
字数 903 2025-08-15 21:32:31
Java代码审计:短信功能安全漏洞分析与防御
概述
本文详细分析Java应用中短信功能常见的安全漏洞,包括短信轰炸和短信越权问题,并提供相应的防御方案。这些漏洞可能导致用户骚扰、企业财务损失或系统安全风险。
短信轰炸漏洞
漏洞描述
短信轰炸漏洞允许攻击者无限获取验证码,造成:
- 对用户的骚扰
- 给企业带来财务损失(短信服务需要付费)
漏洞代码示例
@RequestMapping("/sendCode.json")
public String sendCode(String tel) {
Boolean isSend = sendSmsTools.send(tel); // 直接调用短信发送接口
if (isSend) {
return SuccessJson("发送成功");
} else {
return ErrorJson("发送失败");
}
}
攻击方式
攻击者可以通过以下方式利用此漏洞:
- 抓取前端请求
- 使用Burp等工具重放请求
- 编写自动化脚本反复调用API
防御方案
引入Redis作为缓存层,实现发送频率控制:
public Boolean send(String phone) {
// 检查Redis中是否已有该手机号的记录
String redisPhone = redisService3.getStr(phone);
if(redisPhone != null) {
return false; // 已有记录则驳回请求
}
// 阿里云短信服务调用
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",ACCESSKEYID,ACCESSKEYSECRET);
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
// ...省略短信服务配置代码...
try {
CommonResponse response = client.getCommonResponse(request);
if(response.getHttpResponse().isSuccess()) {
// 发送成功后记录到Redis,有效期15分钟
redisService3.setStrAsMINUTES(phone + "_code", code, 15);
return true;
} else {
return false;
}
} catch(Exception e) {
e.printStackTrace();
return false;
}
}
防御流程
- 前端请求后端发送短信API
- 服务端检查Redis中该手机号是否有发送记录
- 无记录则调用短信服务发送验证码
- 发送成功后,将手机号记录存入Redis(带有效期)
短信越权漏洞
漏洞描述
当系统存在以下情况时可能出现短信越权:
- 登录接口未做验证码暴力破解限制
- 修改密码接口做了验证码错误次数限制
- 使用过的验证码未被及时清除
攻击者可利用已爆破出的验证码在其他功能点(如修改密码)使用,绕过验证码错误次数限制。
漏洞场景
- 前端调用后端发送短信
- 用户收到验证码并登录
- 登录接口验证验证码
- 进入系统
- 攻击者使用同一验证码进行密码修改操作
防御方案
正确流程应包含验证码使用后的清除操作:
- 前端调用后端发送短信
- 用户收到验证码点击登录
- 从Redis获取存储的验证码
- 比较用户输入与存储的验证码
- 删除Redis中存储的验证码
- 允许登录
清除验证码实现
public Boolean clearCode(String phone) {
redisService3.del(phone+"_code");
return true;
}
进阶防御措施
签名算法
为防止验证码暴力猜解,可在接口处添加签名算法:
- 每次调用生成唯一参数
- 重放攻击无法满足唯一性条件
- 注意:签名算法可能被逆向(参见前端审计相关内容)
总结
短信功能安全要点
- 发送频率控制:使用Redis等缓存记录发送状态
- 验证码生命周期管理:使用后立即清除
- 接口防护:添加签名算法防止重放
- 错误次数限制:关键操作需限制验证码尝试次数
审计关键点
审计时应检查:
- 短信发送接口是否有频率限制
- 验证码使用后是否被清除
- 不同功能点的验证码是否隔离
- 是否有防重放机制
通过以上措施,可有效防范短信功能常见的安全漏洞。