SQL注入问题

avatar
作者
猴君
阅读量:0

一、什么是sql注入

public class TestSql { 	     public static void main(String[] args) { 		Scanner inScanner = new Scanner(System.in); 		System.out.println("请输入用户名"); 		String username = inScanner.nextLine(); 		System.out.println("请输入密码"); 		String password = inScanner.nextLine(); 		String sql = "select * from user where username = '"+username+"' and password = '"+password+"'"; 		search(sql); 	}  	public static void search(String sql) { 		try { 			Class.forName("com.mysql.jdbc.Driver"); // 1.加载驱动 			//2.建立连接 			Connection connection = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/login?useUnicode=true&characterEncoding=utf-8", "root", ""); 			//3.创建执行的SQL语句 				 			Statement statement = (Statement) connection.createStatement(); 			//4.执行sql语句 			ResultSet re = (ResultSet) statement.executeQuery(sql); 			//5.处理结果 			if(re.next()) { 				System.out.println("查询成功..."); 			}else { 				System.out.println("查询失败..."); 			} 	                 //6.释放资源 			if(re!=null) { 				re.close(); 			} 			if(statement !=null) { 				statement.close(); 			} 			if (connection !=null) { 				connection.close(); 			} 				 		} catch (Exception e) { 			// TODO Auto-generated catch block 			System.out.println("找不到驱动类,加载失败"); 			e.printStackTrace(); 		}  	} 	 }

以上的程序我们经过测试没什么问题,但是当输入如下数据的时候,一个可怕的问题出现了。

 

数据库中只有一个数据

那么为什么会产生这个现象呢?

我们将拼接好的sql语句拿出来

select * from user where username =' 111' and password = '1' or '1'='1';

我们将SQL语句拿到Navicat运行一下 

        这种通过传参就能改变SQL语句原本规则的操作就是SQL注入,这个在实际开发中当然是危险的,攻击者可以把SQL命令插入到Web表单的输入域或页面请求的查询字符串中,欺骗服务器执行恶意的SQL命令。

二、为什么会产生sql注入问题呢?

        我们可以把sql语句的执行流程大致分为一下几个步骤:

1.本地sql语句拼接

2.发送sql语句给DBMS

3.DBMS进行sql编译

        造成sql注入的原因在于我们在本地拼接了一条“有安全隐患的”sql语句。之后我们将拼接好的sql语句发送给DBMS,DBMS将“有安全隐患”的sql语句进行了编译执行。

这里的重点是:用户的信息参与到了编译过程,而这个信息出现了问题

三、如何解决sql注入问题呢?

        其实解决方法很简单:只要用户提供的信息不参与SQL语句的编译过程,问题就解决了。

要想让用户的信息不参与SQL语句的编译,那么就需要预先对sql语句的框架进行编译,然后再给给sql赋值。预编译完成之后我们的DBMS只需要执行我们的sql语句,没必要再次编译。可以使用java.sql.PreparedStatement接口完成预编译,PreparedStatement是属于预编译的数据库操作对象

使用PreparedStatement需要注意的几点

①:占位符

String sql = "select * from user where username = ? and password = ?";

我们拼写好的sql语句不在使用直接拼接赋值的方式,而是采用 ? 占位符进行代替

②:创建方式

statement.setString(1, usernanme); statement.setString(2, password); 

总体代码如下

public class TestSql { 	 	public static void main(String[] args) { 		Scanner inScanner = new Scanner(System.in); 		System.out.println("请输入用户名"); 		String username = inScanner.nextLine(); 		System.out.println("请输入密码"); 		String password = inScanner.nextLine(); 		String sql = "select * from user where username = ? and password = ?"; 		search(sql,username,password); 	}  	public static void search(String sql,String usernanme,String password) { 		try { 			Class.forName("com.mysql.jdbc.Driver"); // 1.加载驱动 			//2.建立连接 			Connection connection = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/login?useUnicode=true&characterEncoding=utf-8", "root", "2020"); 			//3.创建执行的SQL语句 			 PreparedStatement statement = (PreparedStatement) connection.prepareStatement(sql); 			// 给占位符赋值 			 statement.setString(1, usernanme); 			 statement.setString(2, password); 			 			//4.执行sql语句 			ResultSet re = (ResultSet) statement.executeQuery(); 			//5.处理结果 			if(re.next()) { 				System.out.println("查询成功..."); 			}else { 				System.out.println("查询失败..."); 			} 	                //6.释放资源 			if(re!=null) { 				re.close(); 			} 			if(statement !=null) { 				statement.close(); 			} 			if (connection !=null) { 				connection.close(); 			} 				 		} catch (Exception e) { 			// TODO Auto-generated catch block 			System.out.println("找不到驱动类,加载失败"); 			e.printStackTrace(); 		}  	} 	 }

 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!