🎯 MyBatis执行SQL的深入分析(含完整调用链)
✅ MyBatis注入链路结构
[Controller] → [Service] → [DAO] → [Mapper(XML/注解)] → [SQL执行]
📌 注入可能发生在:Mapper 的 SQL 映射或注解中
- 使用
${}
:直接拼接输入参数,存在 SQL 注入风险。 - 使用
#{}
:预编译处理参数,安全。
🧪 示例场景:用户查询功能存在SQL注入漏洞
👇 1. Controller 层
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private AdminService adminService;
@GetMapping("/search")
public List<Admin> search(@RequestParam String username) {
return adminService.searchByUsername(username);
}
}
- 用户访问:
/admin/search?username=admin
- 参数传入 Service 层
👇 2. Service 层
@Service
public class AdminService {
@Autowired
private AdminDAO adminDAO;
public List<Admin> searchByUsername(String username) {
return adminDAO.findByUsername(username);
}
}
- 调用 DAO,无输入校验
👇 3. DAO 层
@Repository
public class AdminDAO {
@Autowired
private AdminMapper adminMapper;
public List<Admin> findByUsername(String username) {
return adminMapper.selectByUsername(username);
}
}
👇 4. Mapper 接口
public interface AdminMapper {
List<Admin> selectByUsername(@Param("username") String username);
}
👇 5. Mapper XML 配置(存在注入风险)
<select id="selectByUsername" parameterType="String" resultType="Admin">
SELECT * FROM admin WHERE username = '${username}'
</select>
🧩 注解型 SQL 映射(存在注入风险)
这种方式使用 MyBatis 的注解(如 @Select
)在接口中直接编写 SQL,如下注解形式:
@Select("SELECT * FROM admin WHERE username = ${username}")
List<Admin> selectByUsername(@Param("username") String username);
🔴 实际SQL:
SELECT * FROM admin WHERE username = 'admin' OR '1'='1'
💥 构造攻击Payload
/admin/search?username=admin' OR '1'='1
可绕过身份验证,查询全部用户。
🔧 安全修复建议
<select id="selectByUsername" parameterType="String" resultType="Admin">
SELECT * FROM admin WHERE username = #{username}
</select>
@Select("SELECT * FROM admin WHERE username = #{username}")
✅ #{}
使用预编译参数,防止注入。
🔍 实战红队审计步骤
- 🔍 查找输入入口(Controller)
- 🔗 跟踪参数传递链(Service → DAO → Mapper)
- 📄 审计 Mapper XML/注解中的 SQL
- 🧪 构造Payload测试是否可注入
🛡 防御建议汇总
风险点 | 修复方式 | 说明 |
---|---|---|
${param} | 替换为 #{param} | 避免字符串拼接 |
order by 动态排序 | <choose> 限制字段选择 | 控制字段范围 |
like 模糊查询 | 使用 CONCAT('%', #{value}, '%') | 安全拼接 |
in 条件查询 | 使用 <foreach> 实现集合传参 | 安全高效 |
🔚 总结
MyBatis 的 SQL 注入常因 ${}
使用不当或动态SQL拼接导致,从 Controller 到 XML 是一条完整的攻击链。建议开发和安全团队:
- 全面替换
${}
为#{}
; - 动态语句使用白名单控制;
- 对高风险字段进行正则验证;
- 辅以全局过滤器提升防御强度。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容