今天我们来谈个数据库注入问题
具体体现
注入定义在上面的传送门里了,我就不多嘴了
就以我上一篇最后的代码为例
其实是及其不安全的,很容易被注入
怎么实现呢?
篡改输入数据
正常的数据库交互肯定是要用户进行输入,数据库获得指令,并进行输出
比如以下登录函数(其内部登录SQL函数我就不具体写了)
public static void login(String name,String password){
Connection conn = null;
Statement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
//SELECT * FROM users WHERE `NAME` = 'makerjack' AND `password` = '123456'
String sql = "SELECT * FROM users WHERE `NAME` = '"+name+"' AND `password` = '"+password+"'";
re = st.executeQuery(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,re);
}
}
对应SQL应该是这样的

正常的登录(用户输入)及结果应该如下

但如果我们用这个语句呢
login(" ' or '1=1"," ' or '2=2");
数据全出来了!
“他说他是乱打的……”
“他可不是乱打的嗷”

不够直观?
放到MySQL里面就是
SELECT * FROM users WHERE `NAME` = ' ' OR '1=1' AND `password` = ' ' OR '2=2'
直接利用or进行恒等判断,使得判定语句恒成立
如此直接套取了数据库的数据,实现SQL注入
如此一想,这很容易被攻击注入呀,该怎么办呢?
使用
PreparedStatement对象
其可以避免SQL注入且效率更高!
PreparedStatement对象
PreparedStatement对象可以防止SQL注入。效率也更高(以下简称PS)

其是继承Statement类,所以基本操作与Statement近似,创建变量也是如此
PreparedStatement st = null;
只是在赋值的时候,其操作需要预编译SQL
String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";
//使用?作为占位符
st = conn.prepareStatement(sql);//预编译sql,先写SQL,不执行
在这之后进行具体字段赋值
st.setInt(1,5);
st.setString(2,"jack");
st.setString(3,"123456");
st.setString(4,"123456@qq.com");
//注意: java.sql.Date() 库是sql 需要导入java.sql.Date
// java.Date() 库是util 需要导入java.util.Date
st.setDate(5,new java.sql.Date(new Date().getTime()));
增加数据如此,删 改 查 亦然。
那么当初那个登录的函数应该如下:
public static void login(String name,String password){
Connection conn = null;
PreparedStatement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
String sql = "SELECT * FROM users WHERE NAME = ? AND PASSWORD = ?";
st = conn.prepareStatement(sql);
st.setString(1,name);
st.setString(2,password);
re = st.executeQuery();
while (re.next()){
System.out.println("id="+re.getObject("id"));
System.out.println("name="+re.getObject("NAME"));
System.out.println("pwd="+re.getObject("PASSWORD"));
System.out.println("email="+re.getObject("email"));
System.out.println("birth="+re.getObject("birthday"));
System.out.println("=====================================");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,re);
}
}
主函数中调用登录函数(第一个是正常,第二个是注入)
public static void main(String[] args) {
login("maker","123456");
login(" ' ' or 1=1","123456");
}

测试结果如上图,第二个注入式登录没有任何结果返回
也没有报错
PreparedStatement防注入本质
其在setObjective() – 包括int String
时会把传递进来的参数当做字符处理
针对类似单引号 ’ 的转义字符,会直接转义处理掉
所以无法实施条件语句篡改
本文主要探讨数据库注入问题,以登录函数为例,展示了通过篡改输入数据实现SQL注入的方法,如利用or进行恒等判断套取数据库数据。为解决该问题,介绍了PreparedStatement对象,它可避免SQL注入且效率更高,还阐述了其防注入的本质是对传递参数进行字符处理和转义。
26万+

被折叠的 条评论
为什么被折叠?



