JDBC如何避免SQL注入
一 . 什么是SQL注入
SQL注入(SQL Injection)是一种代码注入技术,它允许攻击者将或“注入”恶意的SQL命令到后端数据库引擎执行。这些恶意的SQL命令可以执行未授权的数据库查询、修改数据、管理数据库服务器上的文件系统、执行管理操作(如关闭数据库服务)等,从而可能对网站或应用程序造成严重的安全威胁。
假设有一个简单的Web应用程序,它使用以下SQL查询来根据用户提供的用户名查找用户信息:
SELECT * FROM users WHERE username = '' + @username + ''
如果用户输入了admin'--
(注意末尾的--
是SQL注释的开始),那么生成的SQL查询将变为:
SELECT * FROM users WHERE username = 'admin'--'
由于--
之后的任何内容都被视为注释,因此查询实际上变成了:
SELECT * FROM users WHERE username = 'admin'
这允许攻击者绕过正常的验证逻辑,直接以admin
用户的身份检索信息,即使他们不知道admin
用户的密码。
二 . 如何避免?
使用PreparedStatement解决SQL注入问题
PreparedStatement 在 Java 中是避免 SQL 注入的一种有效手段。它通过使用参数化查询来工作,这种方式确保了用户输入被当作数据而不是 SQL 代码的一部分来执行。以下是 `PreparedStatement如何避免 SQL 注入的详细解释:
1. 参数化查询
当你使用PreparedStatement 时,你首先编写一个带有占位符(通常是 ?
)的 SQL 语句。然后,你通过 set
方法(如 setInt()
, setString()
等)为这些占位符提供具体的值。这些值在运行时被绑定到 SQL 语句中,而不是在 SQL 语句被解析或编译时。
2. 编译一次,执行多次
PreparedStatement对象在数据库中被编译一次,但可以被执行多次,每次执行时只需替换占位符的值。这种机制不仅提高了性能(因为避免了重复的编译),还增强了安全性,因为 SQL 语句的结构在编译时就已经固定,不会被后续的用户输入所改变。
3. 防止 SQL 注入
由于 PreparedStatement
使用占位符和参数绑定机制,用户输入的数据被当作数据值来处理,而不是 SQL 代码的一部分。这意味着即使输入中包含 SQL 关键字、特殊字符或注释等,它们也不会被数据库解析为 SQL 语句的一部分,从而避免了 SQL 注入攻击。
我们来看下列代码 , 这里进行了一个登录的校验 , 使用
connection.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?");
这样就可以有效避免sql注入问题
package com.Month08.Day_11;import com.Month07.Day_02.Class1;import java.sql.*;
import java.util.Scanner;public class HDBC {public static void main(String[] args) throws ClassNotFoundException, SQLException {// statement.executeUpdate("insert into user(username , password) values (123,123)");select();}public static void select()throws ClassNotFoundException, SQLException {Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");int username = sc.nextInt();System.out.println("请输入密码");int password = sc.nextInt();Class.forName("com.mysql.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users","root","root");PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?");preparedStatement.setInt(1,username);preparedStatement.setInt(2,password);ResultSet resultSet = preparedStatement.executeQuery();while (resultSet.next()){System.out.println("登陆成功");}connection.close();}
}