预编译
首先,什么时编译预处理机制? 字面理解就是预先进行编译
那么,预编译处理机制有什么用? 可以解决SQL注入问题
那么,问题又来了,什么是sql注入呢? 简单来说就是应用程序没有对用户输入数据进行校验或者过滤不严格
内容讲解及代码展示
了解什么时预编译和sql注入,在这里我用jdbc实现用户登录原理来给大家讲解预编译和sql注入
大家可以预先了解
jdbc上手(上)
jdbc上手(下)
首先,先回顾一下jdbc步骤
- 加载连接数据库驱动
- 与数据库建立连接
- 生成与数据库对话的对象
- 与数据库进行对话
- 收尾
然后,看一下没有预编译的效果
原理:通过jdbc与数据库建立连接,当我们输入用户名及密码时,在数据库进行校验,如果数据库有这条记录即为登录成功,否则为登录失败
数据库表
import java.sql.*;
import java.util.Scanner;
public class jdbctest {
public static void main(String[] args) throws SQLException {
Scanner scanner=new Scanner(System.in);
//1加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.err.println("驱动加载失败!!!");
e.printStackTrace();
}
//2建立与数据库连接
Connection conn=null;
try {
conn= DriverManager.getConnection("jdbc:mysql://localhost:33060/mytest","root","Root");
} catch (SQLException e) {
System.err.println("数据库连接建立失败!!!");
e.printStackTrace();
}
//3根据连接生成与数据库对话的对象
Statement stmt=null;
try {
stmt=conn.createStatement();
} catch (SQLException e) {
System.err.println("生成与数据库对话的对象失败!!!");
e.printStackTrace();
}
//4与数据库进行对话
ResultSet res=null;
while(true){
System.out.println("请输入用户名和密码!!");
String username=scanner.next();
String userpwd =scanner.next();
String execuetquery=" select * from users where nuername='"+username+"' and userpwd='"+ userpwd +"' ";
res=stmt.executeQuery(execuetquery);
if (res.next()){
System.out.println("登录成功!!");
System.out.println("您的账户为:"+res.getObject("nuername")+"您的密码为:"+res.getObject("userpwd"));
break;
}else{
System.out.println("登录失败!!");
}
}
//5收尾
if (res!=null){
res.close();
}
if (stmt!=null) {
stmt.close();
}
if (conn!=null) {
conn.close();
}
}
}
在我们的数据库中只有两条记录,所以正常情况下只有用户名和密码与这两条记录中的一条符合时才会显示登录成功,但是,这个是后就会出现sql注入问题,大家看下面的截图!
我随便输入了一个用户名,输入的密码在数据库中也没有记录,但是却登录成功,这样就出现了sql注入漏洞
下面,我为大家详细解释sql注入漏洞
利用SQL语句的字符串拼接过程将(OR 永真条件)强行注入到原查询SQL中,导至原有查询条件全部失效
的处理手法。
例如:String querySQL = "SELECT * FROM Users WHERE username='"+userName+"' AND
userpwd='"+userPwd+"'";
正常应输入正确的用户名和密码即可组合成正确的查询语句,效果如下:SELECT * FROM Users
WHERE usernane='admin' AND userPwd='admin';
如发生SQL注入漏洞处理,则输入的信息可能为('OR'1'='1),
最终注入效果如下:SELECT * FROM Users WHERE usernane='errorname' AND
userPwd='errorpwd'OR'1'='1';
下面给大家展示具有预编译处理的代码(只是在第3-5步与上面的代码有差异):
import java.sql.*;
import java.util.Scanner;
public class jdbctest2 {
public static void main(String[] args) throws SQLException {
Scanner scanner=new Scanner(System.in);
//1加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.err.println("驱动加载失败!!!");
e.printStackTrace();
}
//2建立与数据库连接
Connection conn=null;
try {
conn= DriverManager.getConnection("jdbc:mysql://localhost:33060/mytest","root","Root");
} catch (SQLException e) {
System.err.println("数据库连接建立失败!!!");
e.printStackTrace();
}
//3根据连接生成与数据库对话的支持预编译处理的对象
String Query="select * from users where nuername=? and userpwd=?"; //用?代替要填入的内容
PreparedStatement pstmt=null;
pstmt=conn.prepareStatement(Query);
pstmt.setObject(1,"");
//4与数据库进行对话
ResultSet res=null;
while(true){
System.out.println("请输入用户名和密码!!");
String username=scanner.next();
String userpwd =scanner.next();
pstmt.setObject(1,username);
pstmt.setObject(2,userpwd);
res=pstmt.executeQuery();
if (res.next()){
System.out.println("登录成功!!");
System.out.println("您的账户为:"+res.getObject("nuername")+"您的密码为:"+res.getObject("userpwd"));
break;
}else{
System.out.println("登录失败!!");
}
}
//5收尾
if (res!=null){
res.close();
}
if (pstmt!=null) {
pstmt.close();
}
if (conn!=null) {
conn.close();
}
}
}
在生成对象时,生成的是支持预编译的对象,用?代替内容进行预编译,然后用户输入的信息就不会参与到之前的sql语句中。这样就起到了预编译预防sql注入的作用!!