sql注入
SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
-- 代码中的SQL语句
"SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";
-- 将用户输入的账号aaa和密码:a' or '1'='1拼接后
"SELECT * FROM user WHERE name='aaa' AND password='a' or '1'='1';"
我们让用户输入的密码和SQL语句进行字符串拼接。用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义,以上问题称为SQL注入。 要解决SQL注入就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。
防止sql注入的解决方法:PreparedSatement预编译对象
(1)PreparedSatement的执行原理
我们写的SQL语句让数据库执行,数据库不是直接执行SQL语句字符串。和Java一样,数据库需要执行编译后的SQL语句(类似Java编译后的字节码文件)。
1.statement对象每执行一条SQL语句都会先将这条SQL语句发送给数据库编译,数据库再执行
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO users VALUES (1, '张三', '123456');");
stmt.executeUpdate("INSERT INTO users VALUES (2, '李四', '666666');");
上面2条SQL语句我们可以看到大部分内容是相同的,只是数据略有不一样。数据库每次执行都编译一次。如果有1万条类似的SQL语句,数据库需要编译1万次,执行1万次,显然效率就低了。
public class JdbcPrecompile {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement preparedStatement =null;
try {
conn = JdbcUtilDemo02.getConnection();
String sql="insert into user(name,username,password) values (?,?,?)";
//预编译sql语句
preparedStatement = conn.prepareStatement(sql);
//设置sql语句中的参数
preparedStatement.setString(1,"张三");
preparedStatement.setString(2,"spsglz");
preparedStatement.setString(3,"123456");
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//关流
}
}
}
prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。相当于调用方法多次传入不同的参数。
(2)PreparedSatement的好处
1.prepareStatement()先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。减少SQL编译次数,提高效率。
2.安全性更高,没有SQL注入的隐患。
3.提高了程序的可读性
(3)PreparedSatement的基本使用
PreparedStatement prepareStatement(String sql)
//会先将SQL语句发送给数据库预编译。PreparedStatement对象会引用着预编译后的结果。
void setDouble(int parameterIndex, double x)
//将指定参数设置为给定 Java double 值。
void setFloat(int parameterIndex, float x)
//将指定参数设置为给定 Java REAL 值。
void setInt(int parameterIndex, int x)
//将指定参数设置为给定 Java int 值。
void setLong(int parameterIndex, long x)
//将指定参数设置为给定 Java long 值。
void setObject(int parameterIndex, Object x)
//使用给定对象设置指定参数的值。
void setString(int parameterIndex, String x)
//将指定参数设置为给定 Java String 值。
ResultSet executeQuery()
//在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的ResultSet对象。
int executeUpdate()
//在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言DML语句
//比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。
(4)PreparedSatement使用步骤
-
- 编写SQL语句,未知内容使用?占位:
"SELECT * FROM user WHERE name=? AND password=?;";
- 获得PreparedStatement对象
- 设置实际参数
- 执行参数化SQL语句
- 关闭资源
- 编写SQL语句,未知内容使用?占位: