使用PreparedStatement防止SQL注入

关于SQL注入

什么是SQL注入

由于jdbc程序在执行的过程中sql语句在拼装时使用了由页面传入参数,如果用户恶意传入一些sql中的特殊关键字,会导致sql语句意义发生变化,这种攻击方式就叫做sql注入,参考用户注册登陆案例。

首先看一下以下代码:

String sql = "select* from users where username='" + userName  
                + "' and password='" + passWord+"'";  
        Connection conn = null;  
        Statement state = null;  
        ResultSet result;  
        conn = JdbcUtil.getConnection();  
        System.out.println(sql);  
        try {  
            state = conn.createStatement();  
            result = state.executeQuery(sql);

这是一段根据传入用户名,密码查找用户表的代码。

在做用户登录的验证的时候,我们可难会根据用户所填写的用户名和密码在后台拼成一条SQL语句执行,去查用户表:

select * from users where username='张三' and password='小张 '

如果能查出结果则表示验证成功,允许登陆,否则账号或密码错误不允许登录。那么在组成这条语句的过程中会存在一个叫做SQL注入的问题,就是用户在输入用户名或密码的时候填写某些内容使得后台接成的SQL语句语义有所变化。

举个例子,在没有防止SQL的情况下:假如我们知道一个用户叫做张三,但是不知道这个用户的密码是什么,我们依然可以在登录的时候在用户输入框写上:张三'#然后密码框任意填:njksad。一点击登陆,会发现居然能够登陆上去。那是为什么呢?

这是因为#在SQL中的意思是注释,那么我们根据上面的情况来分析一下最终拼成的SQL语句是怎样的

select * from users where username='张三'#' and password='njksad'

那就意味着之后的内容都是注释,也就是可以忽略掉那么这条语句真正发挥作用的部分就是

select * from users where username='张三'

直接变成了一条查找张三的语句,完全不用经过密码验证

防止SQL注入攻击

那么怎么才能做到防止SQL注入攻击呢?

在上面那段代码中,Statement的对象是用来执行SQL语句的,Statement有一个子类叫做PreparedStatement,可以做到防止SQL注入攻击,接下来我们来看看PreparedStatement有什么特点以及怎么使用:

PreparedStatement是Statement的孩子,不同的是,PreparedStatement使用预编译机制,在创建PreparedStatement对象时就需要将sql语句传入,传入的过程中参数要用?替代,这个过程会导致传入的sql被进行编译,再传入特殊值也不会有作用了。

而且PreparedStatement使用了预编译机制,sql语句在执行的过程中效率比Statement要高。

String sql = "select* from users where username=? and password=?";  
        Connection conn = null;  
        PreparedStatement state = null;  
        ResultSet result;  
        conn = JdbcUtil.getConnection();  
        System.out.println(sql);  
        try {  
            state = conn.prepareStatement(sql);  
            state.setString(1, userName);  
            state.setString(2, passWord);  
            result = state.executeQuery();

results matching ""

    No results matching ""