您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# MyBatis对SQL注入的防御方法
## 引言
SQL注入(SQL Injection)是最常见的Web安全漏洞之一,攻击者通过构造恶意输入篡改SQL语句逻辑,可能导致数据泄露、数据篡改甚至服务器沦陷。作为主流的Java持久层框架,MyBatis提供了多种机制来防范SQL注入风险。本文将深入剖析MyBatis的防注入原理和具体实践方案。
## 一、SQL注入的基本原理
### 1.1 典型注入案例
```sql
-- 原始SQL
SELECT * FROM users WHERE username = '${param}' AND password = '123456'
-- 攻击者输入 param = ' OR '1'='1
-- 最终执行SQL
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '123456'
MyBatis默认使用JDBC预编译机制:
// Mapper接口
@Select("SELECT * FROM users WHERE username = #{username}")
User findByUsername(@Param("username") String username);
// 实际执行的SQL(参数被替换为?)
PreparedStatement ps = connection.prepareStatement(
"SELECT * FROM users WHERE username = ?");
ps.setString(1, username);
优势: - 参数值与SQL语句分离 - 特殊字符自动转义 - 数据库引擎区分指令和数据
特性 | #{} | ${} |
---|---|---|
处理方式 | 预编译参数 | 字符串替换 |
安全性 | 安全 | 有注入风险 |
适用场景 | 值参数 | 动态表名/列名 |
<!-- 安全方式 -->
<select id="findUser" resultType="User">
SELECT * FROM users WHERE username = #{username}
</select>
<!-- 需要动态SQL时使用OGNL表达式 -->
<select id="orderBy" resultType="User">
SELECT * FROM users ORDER BY ${columnName}
<!-- 必须对columnName做白名单校验 -->
</select>
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
// 安全的批量插入
<insert id="batchInsert">
INSERT INTO users (name, email) VALUES
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.email})
</foreach>
</insert>
处理特殊数据类型时实现TypeHandler接口:
public class XssStringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) {
// 对参数进行XSS过滤
String filtered = HtmlUtils.htmlEscape(parameter);
ps.setString(i, filtered);
}
}
全局拦截器示例:
@Intercepts(@Signature(type= StatementHandler.class,
method="prepare", args={Connection.class,Integer.class}))
public class SqlInjectionInterceptor implements Interceptor {
private static final Set<String> BLACKLIST = new HashSet<>(Arrays.asList(
"drop", "truncate", "shutdown"));
@Override
public Object intercept(Invocation invocation) throws Throwable {
BoundSql boundSql = ((StatementHandler)invocation.getTarget()).getBoundSql();
String sql = boundSql.getSql().toLowerCase();
for (String keyword : BLACKLIST) {
if (sql.contains(keyword)) {
throw new SQLException("检测到危险SQL关键字");
}
}
return invocation.proceed();
}
}
<select id="search" resultType="User">
SELECT * FROM users
WHERE username LIKE CONCAT('%', #{keyword}, '%')
</select>
// Java代码
List<Integer> ids = Arrays.asList(1,2,3);
// Mapper XML
<select id="findByIds" resultType="User">
SELECT * FROM users WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
// 使用Provider实现安全表名校验
@SelectProvider(type = UserSqlProvider.class, method = "findByTable")
List<User> findByTable(@Param("tableName") String tableName);
public class UserSqlProvider {
public String findByTable(Map<String, Object> params) {
String tableName = (String) params.get("tableName");
if (!isValidTableName(tableName)) {
throw new IllegalArgumentException("非法表名");
}
return "SELECT * FROM " + tableName;
}
}
# mybatis-config.xml
<settings>
<setting name="logImpl" value="SLF4J"/>
</settings>
# logback.xml配置
<logger name="org.mybatis" level="DEBUG"/>
MyBatis通过预编译机制为核心,配合正确的开发规范,能有效防范SQL注入风险。但安全是一个整体工程,需要开发者在框架提供的安全基础上,结合业务场景实施纵深防御策略,才能构建真正安全的持久层。
本文共计约3200字,详细覆盖了MyBatis防SQL注入的技术细节和实践方案。实际开发中应结合具体业务场景灵活应用这些防护措施。 “`
这篇文章采用Markdown格式编写,包含: 1. 多级标题结构 2. 代码块示例 3. 对比表格 4. 有序/无序列表 5. 重点内容强调 6. 防御方案分类说明 7. 实际案例演示 8. 最佳实践总结
可根据需要进一步扩展具体案例或添加性能测试数据。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。