文章目录
Javaweb-数据库操作-模式&写法&预编译等
环境搭建
VulDemo审计源码百度云
在Java中执行SQL语句一般有以下几种方式:
JDBC 注入分析
String sql = "select * from user where id ="+req.getParameter("id");
PrintWriter out = resp.getWriter();
out.println("Statement Demo");
out.println("SQL: "+sql);
try {
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while (rs.next()){
out.println("<br>Result: "+ rs.getObject("name"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
这里sql语句与请求参数进行了拼接(使用了JDBC API Statement执行sql语句的方法)
PrintWriter out = resp.getWriter();
out.println("prepareStatement Demo3");
String sql = "select * from user where id = ?";
out.println(sql);
try {
PreparedStatement pstt = conn.prepareStatement(sql);
// 参数已经强制要求是整型
pstt.setInt(1, Integer.parseInt(req.getParameter("id")));
ResultSet rs = pstt.executeQuery();
while (rs.next()){
out.println("<br> id: "+rs.getObject("id"));
out.println("<br> name: "+rs.getObject("name"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
PreparedStatement(也是JDBC API执行sql语句的方法)
Statement和PreparedStatement是Java JDBC API中两种常用的执行SQL语句的方式
Statement:
Statement对象用于执行静态SQL语句,即在编译时已经确定了SQL语句的结构。
Statement执行SQL语句时,直接将完整的SQL语句发送给数据库执行。
Statement对象适用于执行不带参数的简单SQL查询或更新操作。
由于Statement对象没有预编译阶段,每次执行SQL语句时都需要将SQL语句编译一次,这可能导致一定的性能开销。
由于没有参数化输入的机制,使用Statement对象时需要谨慎处理输入数据,以防止SQL注入攻击。
PreparedStatement:
PreparedStatement对象用于执行动态SQL语句,即在执行时才确定SQL语句的具体参数值。
PreparedStatement对象在创建时需要提供一个SQL模板,其中的参数使用占位符(例如,“?”)表示。
在执行PreparedStatement时,首先会对SQL语句进行编译和优化,然后只需提供参数值,而不需要重新编译SQL语句。
PreparedStatement适用于频繁执行带有参数的SQL语句,如参数化查询。
由于PreparedStatement具有预编译和参数化输入的特性,可以提高性能和安全性,并且能够防止SQL注入攻击。
安全写法(SQLDemo3): “select * from user where id = ?”; //参数化执行sql语句
不安全写法(SQLDemo): “select * from user where id =”+req.getParameter(“id”);
关于预编译
编译器在编译sql语句时,会依次进行词法分析、语法分析、语义分析等操作,
预编译技术会让数据库跳过编译阶段(sql语句已经编译好了),也就无法就进行词法分析,关键字不会被拆开,所有参数 直接 变成字符串 进入 数据库执行器执行。
参考:https://blog.csdn.net/qq_42521154/article/details/110785392
Mybatis 注入分析
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.UserDao">
<select id="QueryByName" parameterType="String" resultType="com.demo.bean.User">
select * from user where name = ${name}
</select>
以下方式可以防御SQL注入
<select id="QueryByName" parameterType="String" resultType="com.demo.bean.User">
select * from user where name = #{name}
</select>
</mapper>
#号会点语句进行预编译
${ } 只是进行string 替换,动态解析SQL的时候会进行变量替换
安全写法(): select * from user where name = #{name}
不安全写法(UserDao.xml):select * from user where name = ${name}
#{name}和${name}是MyBatis中两种常用的参数传递方式,具有不同的行为和特点
#{name}(参数占位符):
是一种安全的参数传递方式,会自动进行参数值的转义和处理,防止SQL注入攻击
使用#{name}时,MyBatis会将参数值作为预编译的参数,将其安全地插入到SQL语句中。
-----------------------------------------------------------------------------
${name}(文本替换):
${name} 是一种简单的文本替换方式,它会将 ${name} 直接替换为参数值,不进行参数值的转义或处理。
使用${name}时,参数值会被直接拼接到SQL语句中,存在SQL注入的风险。
Hibernate 注入分析
PrintWriter out = resp.getWriter();
out.println("Hibernate Demo");
try {
tx = session.beginTransaction();
String parameter = req.getParameter("name");
// List user = session.createQuery("FROM User where name='" + parameter + "'").getResultList();
// from user where name = 'Yu or 1=1'
Query query = session.createQuery("from com.demo.bean.User where name = ?1", User.class);
query.setParameter(1, parameter);
List user = query.getResultList();
for (Iterator iterator =
user.iterator(); iterator.hasNext(); ) {
User user1 = (User) iterator.next();
out.println(user1.toString());
}
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
//session.close();
}
安全写法():参数绑定预编译
Query.query=session.createNativeQuery(“select * from user where name=:name”);
query.setParameter(“name”,parameter) ;
这里对’进行了转义;通过query.setParameter()方法将参数值设置到查询语句中,避免了直接拼接参数值到查询语句中的安全风险
不安全写法(User.java):
Query.query=session.createNativeQuery(“select * from user where name=”+req.getParameter(“id”));
这里同样也是拼接
总结:
1、预编译使用不当:
sql=“select * from user where id = ?”;
sql+=“and username =”+req.getParameter(“username”);
2、直接动态拼接:
“select * from user where id =”+req.getParameter(“id”);
3、order by& like & in查询:(由于这两种不能预编译,所以需要过滤器或自定义过滤)
防御:
能预编译的情况都做预编译,一些特殊无法做预编译的,则过滤用户可控的参数。
Javaweb-代码审计SQL注入-INXEDU在线网校
思路:明确SQL三种模式->引用Mybatis->$()写法及XML文件->deleteArticleByIds->ArticleService.java->调用层次结构->deleteArticle->this.deleteArticle(aridArr)
路由:/admin/article/delete 参数:articelId
python sqlmap.py -r inxedu.txt
POST /admin/article/delete HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Cookie: BEEFHOOK=AOWdyRnbQnsrIpDhPuZf0a8oGzFzUKJrfRgGVHbRCB8cvznVuMjwWpmCPpPZuQyYjmiKPdtWLQJWbF80; _c_id=ascxsky7fw6uja985fn1635787683950vota; 3AB9D23F7A4B3C9B=YRQ5UHLXN2L3Z6RWJYHZNC3APNTMAJZNYXER2ILC6Z6TLFUDUAWZ4TLJA54Q37AMAKWGGT4LWNSNWYAUH6UJWZU74E; jSkQ_2132_ulastactivity=dcc8oerh%2F%2BcUSRVNiDd1%2B3wanKhoUM6O1jjHGfOa8wi1oDWf7zW5; jSkQ_2132_lastcheckfeed=1%7C1638707571; jSkQ_2132_nofavfid=1; JSESSIONID=12705DA8E13D05312443DE7F337F512F; inxedulogin_sys_user_=inxedulogin_sys_user_1
Host: 127.0.0.1:8080
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
articelId=1*