查看PreparedStatement最终执行的SQL

首先需要声明,本文纯属一个毫无远见和真才实学的小小开发人员的愚昧见解,仅供用于web系统安全方面的参考。

1、前提

很多同学都希望PreparedStatement 打印出最终执行的SQL,可能用于学习,也可能用于系统维护,也有可能用于其他的目标; 我也有这个想法和需求,但是经过多次实践和尝试,我发现在我的能力范围,我是无法实现的。 于是我找到了一个工具,log4jdbc ,这个工具能够切入JDBC层,对实际SQL执行前,把SQL抽出来。 这个工具相当强大,不过最终的运行结果会超出你的设想……. PreparedStatement 打印出最终执行的SQL。 利用log4jdbc工具。

2、使用log4jdbc工具

详见我的博客: 好记性不如烂笔头14-使用log4jdbc显示完整SQL语句和执行时间

有详细的说明

3、测试用的JSP页面>>===>>>用户名:=>=>>==>></body></html>4、利用log4jdbc工具打印PreparedStatement的最终执行SQL的JAVA代码package com.struts2;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import javax.servlet.http.HttpServletRequest;import org.apache.commons.dbutils.DbUtils;import org.apache.commons.lang.xwork.StringUtils;import org.apache.struts2.ServletActionContext;import com.db.DBUtils;import com.db.Log4JDBCTest;import com.opensymphony.xwork2.ActionSupport;/** * 一个简单的登陆认证功能,,仅用于说明情况 * * @author 范芳铭 */{serialVersionUID = 7854497526623985504L;public String execute() throws Exception {System.out.println(“—LoginAction start–“);HttpServletRequest request = ServletActionContext.getRequest();String username = request.getParameter(“username”);String password = request.getParameter(“password”);request.setAttribute(“username”, username);// 用户名和密码如果有一个为空,返回失败if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {return “false”;}Connection con = null;try {//con = DBUtils.getConnO2O();con = Log4JDBCTest.getConnBM();String sql = “select count(*) as count from ffm_user where “+ “username = ? and password = ? “;System.out.println(“打印出来的SQL:” + sql);PreparedStatement ps = con.prepareStatement(sql);ps.setString(1, username);ps.setString(2, password);ResultSet rs = ps.executeQuery();while (rs.next()) {int count = rs.getInt(“count”);//不考虑密码加密的问题,如果在数据库中找到一个结果,那么就当密码正确if (count > 0) {return “success”;} else {return “false”;}}} catch (Exception e) {e.printStackTrace();} finally {DbUtils.closeQuietly(con);}return “success”;}}5、启动应用,运行

输入:用户名:ffm,密码:1 打印出来的SQL:select count(*) as count from ffm_user where username = ? and password = ? Log4jdbc打印出来的SQL: select count(*) as count from ffm_user where username = ‘ffm’ and password = ‘1’ {executed in 147 msec}

是不是感觉很不错,确实满足了我们的需求

我们换一种输入吧。 输入:用户名:’ or 0=’0’– ,密码输入:2 或者其他任意 打印出来的SQL:select count(*) as count from ffm_user where username = ? and password = ?

Log4jdbc打印出来的SQL: select count(*) as count from ffm_user where username = ‘’ or 0=’0’–’ and password = ‘2’ {executed in 331 msec}

看起来也很不错,但是这里有一个巨大的坑在里面。 仔细观察程序,输入:用户名:’ or 0=’0’– ,密码输入:2 是无法通过验证的,而 Log4jdbc打印出来的SQL,放在plsql中执行,是通过验证的。 也就是说,实际执行的SQL,不是我们所打印出来看到的。

6、结论

**Log4jdbc 只能打印PreparedStatement 最终执行的常规SQL,不能打印带有特殊字符的SQL。 使用PreparedStatement的参数的方法,是能够针对性的防御SQL注入的。**

放弃等于又一次可以选择的机会。

查看PreparedStatement最终执行的SQL

相关文章:

你感兴趣的文章:

标签云: