简介:
参数化SQL语句发送接口;
在sql语句中使用 ' ? ' 占位符表示参数;
只会进行
一个对象绑定一条SQL语句。
所在包:
Module java.sql
Package java.sql
Interface PreparedStatement
继承关系:
public interface PreparedStatement
extends Statement
创建方法:
使用的是Connection接口中的方法:
PreparedStatement prepareStatement(String sql) throws SQLException
sql:绑定的模板,一个SQL语句可能包含一个或多个'?'在参数占位符
设置参数的方法:
public void setString(int parameterIndex, String x) throws SQLException
这是一个设置String类型参数的方法:
parameterIndex: 第几个参数
x:参数的值
setString()是设置String类型的参数,那么可以想到setDouble()就是设置double类型的参数,一次类推,数据库中需要什么类型的参数就使用对应的方法。
执行方法:
PreparedStatement执行SQL的方法没有参数,因为它在创建的时候就和SQL语句绑定在一起的了,换句话说就是只能执行创建时绑定的那条SQL语句。
和Statement对象一样:
public ResultSet executeQuery() throws SQLException
执行这个方法返回ResultSet对象;
public int executeUpdate() throws SQLException
执行这个方法返回影响的行数。
SQL攻击:
SQL攻击就是利用程序传递参数时的识别语句漏洞进行跨权限访问。
做一个简单的案例:
在MySQL数据库中创建一个表:
create table t_user (
username VARCHAR(50),
`password` VARCHAR(50)
);
INSERT INTO t_user VALUE('zs','123');
INSERT INTO t_user VALUE('ls','123');
INSERT INTO t_user VALUE('ww','123');
创建一个方法连接数据库:
public boolean login2(String tusername,String tpassword) throws Exception {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 四个参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/db1";
String username = "root";
String password = "747699";
//加载驱动
Class.forName(driverClassName);
// SQL模板
String sql = "select * from t_user where username='"+tusername+"' and password='"+tpassword+"'";
// 注册驱动
con = DriverManager.getConnection(url, username, password);
// 获取SQL对象
st = con.createStatement();
// 发送SQL获得ResultSet对象
rs = st.executeQuery(sql);
return rs.next(); // 存在着返回true
} finally { // 关闭资源
if (rs != null)
rs.close();
if (st != null)
st.close();
if (con != null)
con.close();
}
}
然后创建测试方法:
@Test
public void fun1() throws Exception {
boolean isOk = login2("zs", "123");
System.out.println(isOk);
}
结果:
返回true就说明输入的参数在数据库中;
那么如果把传入的参数换一种方式:
@Test
public void fun1() throws Exception {
boolean isOk1 = login2("zs", "123");
boolean isOk2 = login2("ls", "123");
boolean isOk3 = login2("a' or 'a'='a", "a' or 'a'='a");
System.out.println(isOk1);
System.out.println(isOk2);
System.out.println(isOk3);
}
再查看输出结果:
可以发现还是返回的true,再看SQL语句就能明显的找出问题了,因为在SQL语句识别判断的时候,使用的是 or 'a'='a' 永真的语句,那么根本不用知道用户名和密码就能直接进入访问。
所以为了杜绝这种问题,就需要使用PreparedStatement接口将SQL语句参数化。
SQL语句参数化:
同样先创建方法连接数据库:
public boolean login1(String tusername, String tpassword) throws Exception {
Connection con = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
// 四个参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/db1";
String username = "root";
String password = "747699";
//加载驱动
Class.forName(driverClassName);
// SQL模板
String sql = "select * from t_user where username=? and password=?";
// 注册驱动
con = DriverManager.getConnection(url, username, password);
// 获取SQL对象
st = con.prepareStatement(sql);
// 设置参数
st.setString(1, tusername); // 设置第一个问号
st.setString(2, tpassword); // 设置第二个问号
// 发送SQL获得ResultSet对象
rs = st.executeQuery();
return rs.next(); // 存在着返回true
} finally { // 关闭资源
if (rs != null)
rs.close();
if (st != null)
st.close();
if (con != null)
con.close();
}
}
这里是使用的PreparedStatement对象,然后创建测试方法:
@Test
public void fun1() throws Exception {
boolean isOk1 = login1("zs", "123");
boolean isOk2 = login1("ls", "123");
boolean isOk3 = login1("'a' or 'a'='a'", "'a' or 'a'='a'");
System.out.println(isOk1);
System.out.println(isOk2);
System.out.println(isOk3);
}
查看结果:
这下就不能通过判断了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)