Java代码审计篇:SQL注入

本文探讨了Java中常见的SQL注入漏洞,包括动态拼接、预编译错误、order by注入、模糊查询等问题,并提供了防范方法。强调了预编译处理的重要性,以及在遇到order by等特殊场景时如何手动过滤参数。同时,提到了MyBatis中的SQL注入风险,如like查询和in参数的安全处理。文章最后讨论了SQL注入的修复策略和安全学习资源。

一、常见SQL注入
1、sql语句动态拼接
示例代码:

String id=request.getParameter("id");
res = st.executeQuery("SELECT * FROM \"IWEBSEC\".\"user\" WHERE \"id\"="+id);
while(res.next()){
int p = res.getInt("id");
String n = res.getString("username");
String s = res.getString("password");
}

上述代码通过request.getParameter方法获取id值,通过 SELECT * FROM \”IWEBSEC\”.\”user\” WHERE \”id\”=”+id 进行了sql语句的动态拼接。通过executeQuerry执行sql语句,会发现id的参数是可控的并且可以进行sql语句的拼接。
2、预编译错误
示例代码:

`String username="user%' or '1'='1'#";
String id ="2";
String sql = "SELECT * FROM user where id = ?";
if (!CommonUtils.isEmptyStr(username))
sql += " and username like '%" + username + "%'";
System.out.println(sql);
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, id);
rs = preparedStatement.executeQuery();`

上述代码虽然使用了preparestatement预编译,但是在后面的username使用了sql语句拼接的方式,这样会导致sql注入。
3、order by 注入
原理:使用prepareStatement时,order by 后面需要加字段名,字段名不能带引号,带引号会被认为这是一个字符串而不是字段名。PrepareStatement 是使用占位符传入参数的,传递的字符都会有单引号包裹,ps.setString(1, id)”会自动给值加上引号,这样就会导致 order by 子句失效。
示例代码:

```java
`String id ="2 or 1=1";
String sql = "SELECT * FROM user "+ " order by " + id;
System.out.println(sql);
PreparedStatement preparedStatement = conn.prepareStatement(sql);
rs = preparedStatement.executeQuery();`

```
上述代码中当使用“String sql = “SELECT * FROM user “+ “ order by “ + id”进行 id 参数拼接时,就出现了 SQL 注入漏洞。
4、%和模糊查询
原理:在 java 预编译查询中不会对%和
进行转义处理,而%和_刚好是 like 查询的通配符,如果没有做好相关的过滤,就有可能导致恶意模糊查询。
传入的 username 为“”%user%””时,通过动态调试发现数据库在执行时并没有将%进行转义处理,而是作为通配符进行查询。
防范方法:直接将%进行过滤。
5、MyBatis SQL注入之order by
order by 子句不可以进行参数化查询,进而不能使用#{},只能使用${},如果在 MyBatis 的 order by
子句中使用#{},则 order by 子句会失效。
示例代码:

运行效果:

可见,其运行结果并没有排序,然后我们查看一下mybatis的日志发现,使用#{}参数化查询会将 age 进
行单引号包裹而导致 order by 失效。

5、like查询
MyBatis 的 like 子句中使用#{}程序会报错,所以为了避免报错,在开发的时候使用${},当使用like ‘#%{name}%’时,会报错。

而使用like ‘$%{name}%’,时会正常执行。

虽然使用${}可是使程序正常运行,但是${}属于字符串的拼接,存在SQL注入,如果 emp_Name 传
入的是“emp_Name’ union select 1,database(),3 #”就会造成 SQL 注入漏洞。
防范方法:过滤
6、in 参数
MyBatis 的 in 子句中使用#{}参数化查询,会将“select from users where name in
(#{user})”转变为“select 
from users where name like (‘’user1’,’user2’,’user3’,’user4’’)”。为避免这个问题只能用${}。
二、常规注入代码审计
1、找常见关键字,方便快速定位
Statement
createStatement
PrepareStatement
like ‘%${
in (${
select
update
insert
2、查找调用方法,弄清逻辑。
3、找到路径绑定关系,构造payload。
4、二次注入
前期与常规注入代码审计一样,找sql语句看是否存在字符串拼接,如果存在,通过查找参数的调用逻辑,理清逻辑,在构造payload时,先注册一个正常的用户名,但是用户名是带有sql语句的,比如 “ ‘union select user(),2.3# “,此时在登陆的时候就可以显示对应的信息。
三、SQL注入的修复
对于 SQL 注入漏洞,最有效的防御手段便是进行预编译处理,使用预编译处理不仅可以防范 SQL 注入攻击,而且能够提高执行速度。但是如果遇到order by,不能用预编译进行处理的时候,就需要对参数进行手动的过滤。
也可以使用强制类型转换来防止sql注入,比如我们已知id的参数是数字,那我们可以把id强制转换为int类型。有效的防止了SQL注入。

免费领取安全学习资料包!

渗透工具

技术文档、书籍

 

面试题

帮助你在面试中脱颖而出

视频

基础到进阶

环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等

 

应急响应笔记

学习路线

package com.tarena.dingdang.filter; 02 03 import java.io.IOException; 04 import java.util.Enumeration; 05 06 import javax.servlet.Filter; 07 import javax.servlet.FilterChain; 08 import javax.servlet.FilterConfig; 09 import javax.servlet.ServletException; 10 import javax.servlet.ServletRequest; 11 import javax.servlet.ServletResponse; 12 import javax.servlet.http.HttpServletRequest; 13 14 public class AntiSqlInjectionfilter implements Filter { 15 16 public void destroy() { 17 // TODO Auto-generated method stub 18 } 19 20 public void init(FilterConfig arg0) throws ServletException { 21 // TODO Auto-generated method stub 22 } 23 24 public void doFilter(ServletRequest args0, ServletResponse args1, 25 FilterChain chain) throws IOException, ServletException { 26 HttpServletRequest req=(HttpServletRequest)args0; 27 HttpServletRequest res=(HttpServletRequest)args1; 28 //获得所有请求参数名 29 Enumeration params = req.getParameterNames(); 30 String sql = ""; 31 while (params.hasMoreElements()) { 32 //得到参数名 33 String name = params.nextElement().toString(); 34 //System.out.println("name===========================" + name + "--"); 35 //得到参数对应值 36 String[] value = req.getParameterValues(name); 37 for (int i = 0; i < value.length; i++) { 38 sql = sql + value[i]; 39 } 40 } 41 //System.out.println("============================SQL"+sql); 42 //有sql关键字,跳转到error.html 43 if (sqlValidate(sql)) { 44 throw new IOException("您发送请求中的参数中含有非法字符"); 45 //String ip = req.getRemoteAddr(); 46 } else { 47 chain.doFilter(args0,args1); 48 } 49 } 50 51 //效验
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值