PreparedStatement与Statement对比、 SQL 注入漏洞原理及实例分析

测试代码
import java.sql.*;

import org.junit.Test;

/**
 *  PreparedStatement与Statement对比、 PreparedStatement防止sql语句的注入原理与分析
 *  * @author baozq
 *  * 2018年3月14日
 */
public class SelectInject {
	
	   //模拟用户输入
    static String name = "zhangsan\'  or \'3\'=\'3";
    static String password = "123";

    @Test
    public void testByStatement(){
    	

        try{
            //调用Class.forName()方法加载驱动程序
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("成功加载MySQL驱动!");
                
            String url="jdbc:mysql://192.168.85.130:3306/test";    //JDBC的URL    
            Connection conn;

            conn = DriverManager.getConnection(url,    "root","root");
            Statement stmt = conn.createStatement(); //创建Statement对象
            System.out.println("成功连接到数据库!");

          //注意带参的sql语句的书写
            String sql = "SELECT * FROM  user WHERE password='"+password+"' AND  userName='"+name+"'  ";
            
            System.out.println(sql);
            ResultSet rs = stmt.executeQuery(sql);//创建数据对象
                System.out.println("编号"+"\t"+"姓名"+"\t"+"年龄");
                while (rs.next()){
                    System.out.print(rs.getString(1) + "\t");
                    System.out.print(rs.getString(2) + "\t");
                    System.out.print(rs.getString(3) + "\t");
                    System.out.println();
                }
                rs.close();
                stmt.close();
                conn.close();
            }catch(Exception e)
            {
                e.printStackTrace();
            }
    }
    
    
    /**
     * PreparedStatement可以有效地防止sql被注入
     */
    @Test
    public void testByPreparedStatement(){
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
        	
        	 //调用Class.forName()方法加载驱动程序
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("成功加载MySQL驱动!");
                
            String url="jdbc:mysql://192.168.85.130:3306/test";    //JDBC的URL    
           

            conn = DriverManager.getConnection(url,    "root","root");
            //获取连接
           // conn = JdbcUtil.getConnection();
            String sql = "SELECT * FROM  user WHERE password=? AND  userName=?";
            //预编译
            stmt = conn.prepareStatement(sql);
            //设置参数
            
            stmt.setString(1, password);
            stmt.setString(2, name);
            //执行sql
            rs = stmt.executeQuery();
            if(rs.next()){
                //登录成功
                System.out.println("登录成功");
            }else{
                System.out.println("登录失败");
            }
            System.out.println(sql);
            System.out.println(stmt);
            System.out.println(rs);

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            try {
				rs.close();
				  stmt.close();
		            conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
          
        }
    }
}

打印SQL:

SELECT * FROM  user WHERE password='123' AND  userName='zhangsan'  or '3'='3' ;

SELECT * FROM  user WHERE password='123' AND  userName='zhangsan\'  or \'3\'=\'3';

执行结果:




更改测试数据:

    static String name = "zhangsan'  or '3'='3";
    static String password = "123";

执行结果: 同上与上面一致;

总结:

Statement: 当输入‘  或  \'  时 如果通过Statement调用SQL会转换为  ' 与字符串开始结束符号一样 而拼装为可执行SQL造成注入;

PreparedStatement:当输入‘  或  \'  时 如果通过PreparedStatement调用SQL会转换为  \' 与字符串开始结束符号不一样 从而防止SQL注入;

猜你喜欢

转载自blog.csdn.net/bzqgo/article/details/79553847