SQL注入漏洞原理详解以及常见框架的SQL注入防止

目录

1. 原理

2. SQL注入常见构造子句

3.Mybatis 常见错误写法导致的SQL注入

  in`或者like些错误的示例:

3. 使用JPA和Hibernate时


1. 原理

SQL注入漏洞是指由于应用程序未能正确过滤用户提交的数据,在用户提交包含SQL语句的内容时,会被应用程序接收并在数据库上执行,从而达到非法操作数据库的目的。这种攻击手段被称为SQL注入攻击。

这种漏洞主要发生在应用程序与数据库交互的过程中,比如登录验证、数据查询等功能。攻击者通过在用户输入框内输入非法的SQL语句,使得系统误将这些语句作为操作数据库的命令执行,从而获取、修改或者删除数据。

防止SQL注入漏洞的方法包括使用参数化查询、使用预编译的SQL语句、限制SQL查询的权限等。同时,对用户输入的数据进行严格的检查和过滤也是非常重要的防护措施。

SQL注入是一种代码注入技术,攻击者利用应用程序的安全漏洞,将恶意的SQL代码插入到原始SQL查询中,从而在目标数据库中执行非授权的命令。

以下是SQL注入的基本原理:

1. 应用程序将用户输入的数据直接合并到SQL查询中,而没有进行适当的校验或转义。
2. 攻击者尝试通过特殊字符(例如单引号)或特定的SQL关键字,修改原始SQL查询的结构,从而在执行时达到非预期的效果。
3. 攻击者可以利用这种技术,执行各种数据库操作,例如数据泄漏、数据篡改甚至数据库管理权限的获取等。

  考虑以下SQL查询:

String query = "SELECT * FROM users WHERE username =
 '" + username + "' AND password = '" + password + "'";


 

如果攻击者输入“admin' --”作为用户名,原始的SQL查询将变为:

 
SELECT * FROM users WHERE username = 'admin' --' AND password = ''


 

在SQL中,"--"表示注释,所以在执行上面的查询时,密码检查将被忽略,攻击者因此可以以管理员身份登录。

为了预防SQL注入,应始终使用参数化查询或预编译的查询,并避免直接将用户输入合并到SQL查询中。

2. SQL注入常见构造子句

以下是一些常见的SQL注入的例子。请注意,这些只是为了理解SQL注入的方式,并非攻击行为的推广或煽动。请不要尝试在任何非授权的环境中使用这些技术。

1. ' OR '1'='1
2. '; DROP TABLE users; --
3. ' OR 'a'='a
4. '; SELECT * FROM users; --
5. ' AND email IS NULL; --
6. ' OR 'x'='x'; --
7. " OR ""=" 
8. ' OR username='admin' 
9. ' UNION SELECT NULL, NULL, NULL; -- 
10. ' UNION SELECT * FROM users; --
11. ' UNION ALL SELECT * FROM users WHERE 'a' = 'a
12. ' AND 1=0 UNION ALL SELECT null, null, null, CONCAT(USERNAME, ':', PASSWORD) FROM USERS; -- 
13. ' OR 'text' = N'text'; --
14. ' OR 'something' IN ('something'); --
15. ' OR 'text' LIKE 'text'; --
16. " OR ""=""; DROP TABLE users; --
17. ' OR '1'='1'-- 
18. ' OR '1'='1'/* 
19. '' OR '1'='1'; 
20. '' OR '1'='1'; DROP TABLE users; --

在攻击者输入的数据中,有些包含了SQL的控制字符如',",;和--,这些字符的存在可以使得攻击者成功地修改原有的SQL语句,达到注入的目的。比如' OR '1'='1可以使得原有的查询语句总是返回真,'; DROP TABLE users; --则可以删除整个users表。

为了防止SQL注入一般系统进行拦截,还有一些相对比较隐蔽的写法如下

 

1. 利用与操作符--和#来注释掉后面的SQL语句: ' OR 'x'='x' -- ' OR 'x'='x' # 
2. 利用UNION操作符来从其他表中获取信息: ' UNION SELECT * FROM users WHERE 'a' = 'a
3. 使用16进制值: ' OR 0x50=0x50
4. 使用字符编码: ' OR 'a'='a
5. 利用LIKE操作符来模糊匹配: ' OR 'x' LIKE '%
6. 使用SQL中的空格代替: ' OR%20'x'='x
7. 利用SQL函数: ' OR ASCII('a')=97
8. 基于时间的SQL注入: 1' WAITFOR DELAY '0:0:10'--   1' AND BENCHMARK(5000000,ENCODE('MSG','by 5 seconds'))--
9. 使用双重编码: %253Cscript%253Ealert(1)%253C/script%253E
10. 利用数据库的特殊功能(比如Oracle中的Dual表,SQL Server的xp_cmdshell等)

3.Mybatis 常见错误写法导致的SQL注入

 虽然MyBatis帮助我们处理了许多SQL操作,但是如果使用不当,也可能会导致SQL注入的风险。这里有一些常见的MyBatis SQL注入的漏洞:

1. 动态SQL:在MyBatis中,你可以编写动态SQL,如 `<if>`、`<choose>`、`<when>`、`<foreach>`等,但是如果在这些动态SQL中携带的参数没有进行合适的转义或者检查,就可能导致SQL注入。

2. `${}`和`#{}`的不当使用:在MyBatis中,`${}`和`#{}`都可以用来传递参数,但是两者的处理方式不同。`#{}`会将传入的数据看作一个参数,MyBatis会对其进行预处理,从而避免SQL注入;而`${}`则会直接将传入的数据拼接到SQL语句中,如果传入的数据中包含恶意代码,那么就可能导致SQL注入。

3. 使用了MyBatis的`@SelectProvider`、`@UpdateProvider`、`@InsertProvider`和`@DeleteProvider`注解来生成SQL语句,但是在生成SQL语句的方法中没有对参数进行检查和转义。

4. 在`<script>`标签中拼接SQL,若未对参数进行校验或转义,也可能导致SQL注入。

预防措施:

1. 参数处理方式上,尽量使用`#{}`方式传递参数,而避免使用`${}`。
2. 在动态SQL中,要对参数进行必要的检查和转义。
4. 严格控制和过滤用户的输入,对于不符合预期的输入要进行拦截。

例如,有一个动态的 SQL 语句,它基于用户的搜索查询来生成:

 

<select id="findBooksByTitle" resultType="Book">
  SELECT * FROM books 
  <if test="title != null">
    WHERE title = ${title}
  </if>
</select>


 

在这个例子中,`title` 是一个从用户那里获取的参数。如果用户输入的是 `A Tale of Two Cities' OR '1'='1`,那么生成的 SQL 会变成:

 

SELECT * FROM books 
WHERE title = 'A Tale of Two Cities' OR '1'='1'

这个 SQL 语句的意思是选择所有的书,因为 `'1'='1'` 总是为真,所以这就绕过了原本只选择指定 `title` 的限制。这就是一个 SQL 注入的例子。

为了避免这种情况,应该使用 `#{}` 来替换 `${}`,如下所示:

 

<select id="findBooksByTitle" resultType="Book">
  SELECT * FROM books 
  <if test="title != null">
    WHERE title = #{title}
  </if>
</select>

这样,MyBatis 就会对 `title` 参数进行预处理,并使用参数化的查询,防止了 SQL 注入攻击。

  in`或者like些错误的示例:

错误的`in`操作 `${ids}`直接将参数进行字符串替换,如果攻击者将`ids`设置为`1 or 1=1`,则会导致所有的用户数据被查询出来。

 
<select id="findByIds" parameterType="List" resultType="User">
  SELECT * FROM user WHERE id in (${ids})
</select>

正确的做法是使用`<foreach>`标签,如下:

 

<select id="findByIds" parameterType="List" resultType="User">
  SELECT * FROM user WHERE id in
  <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
    #{item}
  </foreach>
</select>


 

错误的`like`操作:

 

<select id="findByName" parameterType="String" resultType="User">
  SELECT * FROM user WHERE name like '%${name}%'
</select>


 

在上面的语句中,`${name}`直接将参数进行字符串替换,如果攻击者将`name`设置为`%' or '1'='1`,则会导致所有的用户数据被查询出来。

正确的做法是对用户输入进行转义,如下:

 

<select id="findByName" parameterType="String" resultType="User">
  SELECT * FROM user WHERE name like CONCAT('%', #{name}, '%')
</select>
 

在上面的语句中,`#{name}`将参数作为预编译的语句处理,可以防止SQL注入。

Spring JdbcTemplate 的这种写法也是同样会导致SQL注入

3. 使用JPA和Hibernate时

当使用JPA和Hibernate时,如果不正确处理查询参数,就有可能导致SQL注入漏洞。以下是一些存在问题的示例:

1. 直接拼接用户输入的值:
 

public boolean validateUser(String username, String password) {
    String query = "SELECT COUNT(u) FROM User u WHERE u.username = '" + username + "' AND u.password = '" + password + "'";
    // ...
}


 用户名和密码直接被拼接到查询语句中,没有任何验证和处理。这种实现容易受到SQL注入攻击,攻击者可以通过输入恶意的值来改变查询的语义。

2. 使用字符串拼接代替参数化查询:

 
public boolean validateUser(String username, String password) {
    String query = "SELECT COUNT(u) FROM User u WHERE u.username = '" + username + "' AND u.password = '" + password + "'";
    Query jpaQuery = entityManager.createQuery(query);
    // ...
}


 
在这个示例中,虽然使用了JPA查询,但是仍然使用字符串拼接来构建查询语句。这种做法与直接拼接用户输入的值没有本质区别,同样容易受到SQL注入攻击。

3. 不使用参数化查询:
 

public boolean validateUser(String username, String password) {
    String query = "SELECT COUNT(u) FROM User u WHERE u.username = :username AND u.password = :password";
    Query jpaQuery = entityManager.createQuery(query);
    jpaQuery.setParameter("username", username);
    jpaQuery.setParameter("password", password);
    // ...
}


在这个示例中,虽然使用了查询参数,但是没有使用命名参数。相反,直接将参数值传递给`setParameter`方法。这种做法仍然存在SQL注入的风险,因为参数值没有经过正确的转义和预编译。

要避免这些问题,应该始终使用参数化查询,并正确地使用命名参数来代替直接拼接用户输入的值。这样可以确保查询参数的安全性,并有效地防止SQL注入攻击。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰点.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值