【java】JDBC中的SQL注入问题和解决方案
创始人
2025-05-29 08:22:39
0

文章目录

  • SQL注入
    • 什么是SQL注入
    • SQL注入的效果的演示
      • SQL注入代码
      • SQL注入效果
    • 如何避免SQL注入
  • PrepareStatement解决SQL注入
    • PreparedStatement的应用
      • 参数标记
      • 动态参数绑定
    • 综合案例
    • PreparedStatement总结
  • 必须使用Statement的情况

SQL注入

什么是SQL注入

在用户输入的数据中有SQL关键字或语法,并且关键字或语法参与了SQL语句的编译。导致SQL语句编译后的条件为true,一直得到正确的结果。这种现象就是SQL注入。

SQL注入的效果的演示

SQL注入代码

package cn.bdqn.demo03;
​
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
​
public class Login {
​public static void main(String[] args) throws ClassNotFoundException, SQLException {//创建Scanner类对象,从控制台获取用户名和密码数据Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String user = sc.nextLine();//使用nextLine()方法获取字符串System.out.println("请输入密码:");String pwd = sc.nextLine();//使用nextLine()方法获取字符串//1、注册驱动Class.forName("com.mysql.jdbc.Driver");//2、获取连接对象String url = "jdbc:mysql://127.0.0.1:3306/java221804";String dbuser = "root";String pssword = "123456";Connection connection = DriverManager.getConnection(url, dbuser, pssword);//3、获取发送SQL语句的对象Statement statement =connection.createStatement();//编写SQL语句String sql = "SELECT * FROM user WHERE username='"+user+"' AND pssword = '"+pwd+"';";//4、执行SQL语句ResultSet resultSet=statement.executeQuery(sql);if(resultSet.next()){System.out.println("用户名和密码正确,登录成功");}else{System.out.println("用户名或密码不正确,登录失败");}//6、关闭资源resultSet.close();statement.close();connection.close();sc.close();}
}

SQL注入效果

输入错误的用户名和密码,提示登录失败:
在这里插入图片描述

输入错误的用户名和密码,提示登录成功:产生了SQL注入

在这里插入图片描述

上面案例代码中,当你的用户名为 abc’ or 1=1;# 密码为123,拼接到SQL语句中,变成如下效果:

  SELECT * FROM user WHERE username='abc' or 1=1;#' AND pssword = '123';

此SQL语句or 后面1=1永远正确,#后面的成了注释,所以这条语句会将表中所有的数据查询出来,然后再做数据判断的时候,就会得到正确结果,从而说用户名和密码正确,登录成功。

如何避免SQL注入

使用PreparedStatement代替Statement可以有效防止SQL注入的发生。由于SQL注入产生的原因是在用户输入数据对SQL整合,整合后再发送到数据库进行编译产生的。

所以为了避免SQL注入,就需要SQL语句在用户输入数据前就进行编译,成为完整的SQL语句,编译完成后再进行数据填充。这个操作需要使用PrepareStatement实现。

PreparedStatement利用预编译的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题。

PrepareStatement解决SQL注入

PreparedStatement接口继承了Statement接口,执行SQL语句的方法与Statement执行SQL语句的方法相同。

PreparedStatement的应用

PreparedStatement的作用:

  • 预编译SQL语句,效率高

  • 安全,避免SQL注入

  • 可以动态的填充数据,执行多个同结构的SQL语句

参数标记

//预编译SQL语句,SQL中的所有参数由?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。

String sql = “select * from user where userName = ? and pssword=?;”;

PreparedStatement preparedStatement = connection.prepareStatement(sql);

动态参数绑定

preparedStatement.sexXxx(下标,值):参数下标从1开始,为指定参数下标绑定值。Xxx表示数据类型。

//绑定参数,有多少个?绑定多少个参数值

preparedStatement.setString(1, userName);

preparedStatement.setString(2, pwd);

综合案例

package cn.bdqn.demo02;
​
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
​
public class PreparedStatementDemo01 {
​public static void main(String[] args) throws ClassNotFoundException,SQLException {
​Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String userName = sc.nextLine();System.out.println("请输入密码:");String pwd = sc.nextLine();
​// 1、注册驱动Class.forName("com.mysql.jdbc.Driver");// 2、获得连接String url = "jdbc:mysql://localhost:3306/java2217";String user = "root";String pssword = "123456";Connection connection = DriverManager.getConnection(url, user, pssword);// 3、获取发送SQL对象String sql = "select * from user where userName = ? and pssword=?;";PreparedStatement preparedStatement = connection.prepareStatement(sql);// 4、绑定参数,有多少个?绑定多少个参数值preparedStatement.setString(1, userName);preparedStatement.setString(2, pwd);// 5、执行SQL语句,并处理结果ResultSet resultSet = preparedStatement.executeQuery();if (resultSet.next()) {System.out.println("用户名和密码正确,登录成功");} else {System.out.println("用户名或密码错误,登录失败");}// 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关resultSet.close();preparedStatement.close();connection.close();sc.close();}
}

PreparedStatement总结

PreparedStatement主要有如下的三个优点:

  • 可以防止sql注入
  • 由于使用了预编译机制,执行的效率要高于Statement
  • sql语句使用?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅.

PreparedStatement 与Statment比较:

  • 语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
  • 效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
  • 安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。

必须使用Statement的情况

    当sql语句中必须用到字符串拼接时,则必须使用Statement
public static void main(String[] args) {Scanner s = new Scanner(System.in);System.out.print("升序输入asc,降序输入desc:");String order = s.nextLine();// 定义变量Connection connection = null;Statement statement = null;ResultSet rs = null;try {// 注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 获取连接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/MyTest","root", "********");// 获取数据库操作对象statement = connection.createStatement();// 执行sqlString sql = "select * from emp order by sal " + order;rs = statement.executeQuery(sql);// 处理查询结果集while(rs.next()){String ename = rs.getString("ename");double sal = rs.getDouble("sal");System.out.println("姓名:" + ename + ",薪资:" + sal);}} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();} finally {// 释放资源if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...