什么是SQL注入:
由于dao层中执行的SQL语句是拼接出来的,其中一部分内容是用户从用户端输入的,当传入数据包含SQL关键字时,就有可能通过这些关键字来改变SQL的语义,从而执行一些特殊的操作,这就称为SQL注入问题。
SQL注入攻击演示:
首先我们创建一张用户表,里面包含用户名和密码。
mysql> select * from user;
+----------+----------+
| username | password |
+----------+----------+
| 满满 | 123456 |
+----------+----------+
1 row in set (0.00 sec)
正常查询:
package com.JDBC;
import java.sql.*;
/**
* @Created with IntelliJ IDEA
* @Description:
* @Package: com.JDBC
* @author: FLy-Fly-Zhang
* @Date: 2019/7/6
* @Time: 18:03
*/
public class JDBCDemo1 {
public static boolean login(String userName,String passwd){
boolean result=false;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
String sql="select * from user where username="+userName+"and password="+passwd;
Statement statement=connection.createStatement();
ResultSet resultSet=statement.executeQuery(sql);
if(resultSet.next())
result=true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String name="'满满'"; //注意,数据库字符串需要+单引号
String passwd="123456";
boolean login=login(name,passwd);
if(login){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}
}
//结果,登陆成功
SQL注入攻击查询
package com.JDBC;
import java.sql.*;
/**
* @Created with IntelliJ IDEA
* @Description:
* @Package: com.JDBC
* @author: FLy-Fly-Zhang
* @Date: 2019/7/6
* @Time: 18:03
*/
public class JDBCDemo1 {
public static boolean login(String userName,String passwd){
boolean result=false;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
String sql="select * from user where username="+userName+"and password="+passwd;
Statement statement=connection.createStatement();
ResultSet resultSet=statement.executeQuery(sql);
if(resultSet.next())
result=true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String name="'满满'"; //注意,数据库字符串需要+单引号
String passwd="1=1 or 12345";
boolean login=login(name,passwd);
if(login){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}
}
//结果,登陆成功
如何解决SQL注入问题: 采用预编译的Statement对象处理
PreparedStatement 采用预编译机制将SQL语句的主干和参数分别传输数据库,数据库是可以分辨SQL语句的主干和参数,这样即使SQL中带有关键字,数据库也仅仅将其当参数使用,关键字就不会起作用。
prepareStatement优势:
- 防止SQL注入
- 使用预编译机制,执行效率是高于Statement
- SQL语句中,参数值是通过?形式来替代参数,在使用preparedStatement方法直接进行拼接,相对于SQL直接拼接更加优雅。
Preparedstatement和statement的区别:
- 语法不同:Preparedstatement可以使用预编译的SQL,statement使用静态sql
- 效率不同:Preparedstatement因为使用预编译,因此在执行时,少了大量的解释代码时间
- 安全性:Preparedstatement能解决SQL注入问题。
解决方案代码演示:
package com.JDBC;
import java.sql.*;
/**
* @Created with IntelliJ IDEA
* @Description:
* @Package: com.JDBC
* @author: FLy-Fly-Zhang
* @Date: 2019/7/6
* @Time: 18:03
*/
public class JDBCDemo1 {
public static boolean login(String userName,String passwd){
boolean result=false;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
String sql="select * from user where username=? and password=?";
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1,userName);
statement.setString(2,passwd);
ResultSet resultSet=statement.executeQuery();
if(resultSet.next())
result=true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String name="满满"; //注意,当使用PreparedStatement时,其会自动加单引号,不需要我们在加
String passwd="1=1 or 123456";
boolean login=login(name,passwd);
if(login){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}
}
//结果,登陆失败