SQL注入问题的解决(PreparedStatement)
Posted 一切随缘~~~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入问题的解决(PreparedStatement)相关的知识,希望对你有一定的参考价值。
sql注入的问题
上篇博客用户登录业务简易实现结尾提到了代码的不足:存在SQL注入问题。
下面演示一下什么是SQL,注入问题。(就拿上篇的代码举个例子)
以上为正常现象,但有些“不法分子”抓住了代码的漏洞,干了一些不为人知的事情。
What!竟然登录成功了!发生了甚么?让我们Debug一下,一探究竟。
select * from t_user where username = ‘jiuzhe’ and userpwd = ‘jiuzhe’ or ‘1’=‘1’
‘1’='1’为true,从而导致了整个柿子返回结果为true。
如何解决sql注入的问题(PreparedStatement)
导致SQL注入的根本原因是什么?
用户输入的信息中含有SQL语句的关键字,最为致命的是这些关键字参与了SQL语句的编译过程,
导致SQL语句的原意被扭曲,进而达到SQL注入。
如何解决SQL注入的问题?
只要用户输入的信息不参与SQL语句的编译过程,问题就解决了。
即使用户输入的信息含有SQL语句的关键字,但由于不参与SQL语句的编译过程,那么也起不到作用。
为此,我们要使用Java.sql.PreparedStatement。
PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。
修改后的代码:
public class userLogin2
public static void main(String[] args)
// 初始化界面,返回用户的信息。
Map<String, String> userLoginInfo = initUI();
// 验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "Success" : "False");
private static boolean login(Map<String, String> userLoginInfo)
// 打一个标记
boolean loginSuccess = false;
String loginName = userLoginInfo.get("userLoginName");
String loginPwd = userLoginInfo.get("userLoginPwd");
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdata",
"root", "root");
// 3.获取预编译的数据库操作对象
// SQL语句的框架,其中一个?,表示一个占位符,一个?将来接收一个“值”,注意占位符不能用单引号括起来。
String sql = "select * from t_user where username = ? and userpwd = ?";// sql语句的框架
// 程序运行到此处,会发送sql语句框架传给DBMS,然后DBMS对sql语句进行预编译。
ps = conn.prepareStatement(sql);
// 给占位符?传值(第一个?下标为1,第二个?下表为2。。。。。。)
ps.setString(1, loginName);
ps.setString(2, loginPwd);
// 4.执行sql语句
rs = ps.executeQuery();
// 5.处理查询结果集
if (rs.next())
loginSuccess = true;
catch (ClassNotFoundException | SQLException e)
e.printStackTrace();
finally
// 6.关闭资源
if (rs != null)
try
rs.close();
catch (SQLException e)
e.printStackTrace();
if (ps != null)
try
ps.close();
catch (SQLException e)
e.printStackTrace();
if (conn != null)
try
conn.close();
catch (SQLException e)
e.printStackTrace();
return loginSuccess;
private static Map<String, String> initUI()
// 获取用户信息
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号:");
String userLoginName = sc.nextLine();
System.out.println("请输入密码:");
String userLoginPwd = sc.nextLine();
Map<String, String> userLoginInfo = new HashMap<>();
// 将用户信息存入Map中
userLoginInfo.put("userLoginName", userLoginName);
userLoginInfo.put("userLoginPwd", userLoginPwd);
return userLoginInfo;
对于不法分子,我想说:就这?
Statement和PreparedStatement的对比
- Statement存在SQL注入问题,PreparedStatement解决了SQL注入问题。
- Statement是编译一次执行一次,而PreparedStatement是编译一次,可执行N次,效率较高一些。
- PreparedStatement在编译过程中进行类型的安全检查。
我们以后大部分情况下,都会使用PreparedStatement。
只有在业务方面必须支持SQL注入,进行SQL语句拼接的时候,必须使用Statement。
以上是关于SQL注入问题的解决(PreparedStatement)的主要内容,如果未能解决你的问题,请参考以下文章