赞
踩
在前面我们对数据库增删改查时,我们使用的是Statement方法,但是他是不能防止sql注入的,我们先来了解一下sql注入:
给出如下表
create table users(
usename varchar(20) primary key ,
password varchar(20)
);
再往表中插入数据:
insert into users values('root','123456');
此时我们在设计登录系统时,是需要判断用户名和密码是否可以对上,使用效率高的方法就是查询设置条件 用户名为 xx and 密码为xxx 看是否能返回,能返回说明可以接收到,也就是用户名和密码对得上,如下图所示:
import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; public class Main { public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException { /*这里我使用了方法,包含注册驱动 构建连接等,会放在在最后*/ Connection connection = GetConnection.getConnection(); Scanner sc = new Scanner(System.in); String name = sc.nextLine();//输入用户名 String password = sc.nextLine();//输入密码 /*创建发送sql对象*/ Statement statement = connection.createStatement(); String sql = "Select * from users where `usename`= '" + name + "' and password = '" + password + "';"; /*使用resultSet接收查询到的结果*/ ResultSet resultSet = statement.executeQuery(sql); if (resultSet.next()) { System.out.println("登录成功!"); } else { System.out.println("登录失败!"); } /*关闭资源,这是我定义的方法,会放在最后*/ JdbcUtils.closeAll(connection,statement,resultSet); } }
当我们随便输入时,会提示登录失败!
但我们输入如下代码,就会提示登录成功
dqwdqw’ or 1 = 1;#
这里产生这种情况的原因是,我们在定义sql语句时,是把我们输入的部分聚合成字符串,再去执行语句,当时输入的部分内容有关键字时,他并不会做特殊处理,只会一股脑执行
Select * from users where `usename`= '" + name + "' and password = '" + password + "';
当我们输入 dqwdqw’ or 1 = 1;# 时,就变成了
Select * from users where usename
= ‘dqwdqw’ or 1 = 1; # and password = ‘" + password + "’;
此时#后面的就变成了注释,而select查询时,判断的是哪条语句能使where后面为真,当输入or 1=1 时候,后面就永远为真,所有语句都会存入resultSet中,这时候就会有人说可以将判断设置成resultSet = 1;但是这样就会出现当数据库中真的只有一条语句时,就会登录成功,所以为了避免这种情况,我们使用PreparedStatement来避免sql注入。
先看如下代码:
import java.io.IOException; import java.sql.*; import java.util.Scanner; public class Main { public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException { /*这里我使用了方法,包含注册驱动 构建连接等,会放在在最后*/ Connection connection = GetConnection.getConnection(); Scanner sc = new Scanner(System.in); String name = sc.nextLine();//输入用户名 String password = sc.nextLine();//输入密码 /*创建发送sql对象*/ //Statement statement = connection.createStatement(); //connection.prepareStatement(sql); String sql = "Select * from users where `usename`= ? and password = ?;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1,name); preparedStatement.setString(2,password); /*使用resultSet接收查询到的结果*/ ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { System.out.println("登录成功!"); } else { System.out.println("登录失败!"); } /*关闭资源,这是我定义的方法,会放在最后*/ JdbcUtils.closeAll(connection,preparedStatement,resultSet); } }
此时再输入该代码就不会出现问题:
原因是我们在sql代码执行前对它进行了预编译,此时他缺失的部分是使用占位符替代,而preparedStatement 最大的不同就在这里,他在将输入或者你给定的参数传入sql语句前会将所有的sql关键字转义成非关键字的字符,这样即使你使用关键字也没办法起到关键字的作用。
所以在使用上PreparedStatement的流程也会多一点,首先会被connection方法定义一次,进行预编译,然后再将占位符赋予真实的数值。最后再执行execute更新或者查询操作。
import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class GetConnection { final static Properties PROPERTIES = new Properties(); public static Connection getConnection() throws IOException, ClassNotFoundException, SQLException { //使用 InputStream is = GetConnection.class.getResourceAsStream("/db.properties"); PROPERTIES.load(is);//将is这个输入流的文件读进 properties类对象当中 String driver = PROPERTIES.getProperty("driver"); Class.forName(driver);//注册驱动 String url = PROPERTIES.getProperty("url");//获取 url String username = PROPERTIES.getProperty("username");//获取username String password = PROPERTIES.getProperty("password");//获取password return DriverManager.getConnection(url,username,password); } }
import java.sql.*; public class JdbcUtils { public static void closeAll(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) throws SQLException { if (resultSet != null) { resultSet.close(); } if (preparedStatement != null) { preparedStatement.close(); } if (connection != null) { connection.close(); } } public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) throws SQLException { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。