接上一篇创建mysql数据库连接(java web之mysql数据库与jdbc(1));
1、Statement 对象存在安全隐患:
Statement的执行,其实是进行sql语句的拼接,然后一起执行,不安全实例如下:
package JDBC2; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import JDBCUtil.JdbcUtil;//上一节封装的工具类 public class demo1 { public static void main(String[] args) { //boolean flog = login("lisi","123"); 登录成功 boolean flog = login("lisi","100234khsdf88' or '1=1");//同样登录成功 if(flog){ System.out.println("登录成功"); } else{ System.out.println("登录失败"); } } static Connection conn = null; static Statement st = null; static ResultSet rs = null; public static boolean login(String name,String passwd){ try { conn = JdbcUtil.getConnection(); st = conn.createStatement(); String sql = "select * from userinfo where username='"+ name +"' and passwd='"+ passwd +"'"; rs = st.executeQuery(sql); while(rs.next()){ String username = rs.getString("username"); String password = rs.getString("passwd"); if ("lisi".equals(username)&&"123".equals(password)){ return true; } } } catch (Exception e) { e.printStackTrace(); } finally{ JdbcUtil.relase(rs, conn, st); } return false; } }
在以上代码中login函数中的参数可看做从前端获取到的数据,第一次测试为数据库中存在的账户和密码,第二次为错误的密码,但能成功登陆:
原因:在Statement对sql语句拼接结果如下:
select * from userinfo where username='lisi' and passwd='100234khsdf88' or '1=1'
拼接的sql语句中有数据库关键字or,数据库将 or 作为关键字处理,并不作为字符串处理。1=1为真, 所以整个sql语句就是一个永真的式子。====》在网络安全上称为sql注入漏洞;
2、解决方法:用PreparedStatement对象替换Statement对象
PreparedStatement对象处理sql语句采用占位符,先判断整个sql语句的逻辑是否正确,如果正确再将数据放置于占位符处。实例如下:
package JDBC2; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import JDBCUtil.JdbcUtil;//上一节封装的工具类 public class demo2 { public static void main(String[] args) { boolean flog = login("lisi","123"); //登录成功 //boolean flog = login("lisi","100234khsdf88' or '1=1");//登录失败 if(flog){ System.out.println("登录成功"); } else{ System.out.println("登录失败"); } } static Connection conn = null; static PreparedStatement ps = null; static ResultSet rs = null; public static boolean login(String name,String passwd){ try { conn = JdbcUtil.getConnection(); String sql = "select * from userinfo where username=? and passwd =?"; ps = conn.prepareStatement(sql); ps.setString(1, name);//对占位符进行填充数据 ps.setString(2, passwd); rs = ps.executeQuery(); while(rs.next()){ String username = rs.getString("username"); String password = rs.getString("passwd"); if ("lisi".equals(username)&&"123".equals(password)){ return true; } } } catch (Exception e) { e.printStackTrace(); } finally{ JdbcUtil.relase(rs, conn, ps); } return false; } }
注意:
(1)给占位符赋值 从左到右数过来,1 代表第一个问号, 永远你是1开始。
ps.setString(1, userName);
ps.setString(2, password);
当传入的参数为XXX类型时调用setXXX()函数
(2)rs = ps.executeQuery();
当对数据库进行增、删、更新操作时调用executeUpdate()函数,且不需要接收返回值,
当对库进行查询时,查询的的结果保存在 ResultSet对象中,需要调用getXXX(“属性名”)方法取出值;如:
String username = rs.getString("username"); //username 为表中属性名,其类型为字符串型,因此用 rs.getString("username");