当前位置: 首页 > news >正文

sql注入漏洞

目录

一、SQL注入概述

例子背景

正常情况下的查询

SQL注入攻击

利用优先级进行攻击

二、解决SQL注入

使用PreparedStatement接口

步骤和方法

1. 创建PreparedStatement对象

2. 向占位符传入值

3. 执行SQL语句

示例

总结


SQL 注入是一种常见的网络攻击手段。通俗来讲,很多网站、应用程序等都需要和数据库交互,比如登录时要查询数据库验证用户名和密码是否正确,接下来就以最常见的登录问题入手。

一、SQL注入概述

SQL注入问题本质上是由字符串拼接And与or的优先级造成的(and优先级高于or)

让我们通过一个具体的例子来理解这句话:“SQL注入问题的本质是因为字符串拼接和AND的优先级高于OR”。

例子背景

假设我们有一个简单的登录表单,后端使用如下的SQL查询来验证用户名和密码:

SELECT * FROM users WHERE username = '输入的用户名' AND password = '输入的密码';

如果开发者直接将用户输入拼接到SQL查询中,而不进行任何处理,就可能导致SQL注入问题。

正常情况下的查询

正常情况下,用户输入的用户名和密码如下:

  • 用户名:admin

  • 密码:password123

拼接后的SQL查询如下:

SELECT * FROM users WHERE username = 'admin' AND password = 'password123';

这个查询会检查数据库中是否存在用户名为admin且密码为password123的用户。

SQL注入攻击

攻击者发现可以输入特殊构造的输入来绕过验证。假设攻击者输入如下:

  • 用户名:admin' --

  • 密码:任意值(例如:123456

拼接后的SQL查询如下:

SELECT * FROM users WHERE username = 'admin' --' AND password = '123456';

由于SQL中--是注释符号,--后面的内容会被SQL解析器忽略,所以实际执行的查询变为:

SELECT * FROM users WHERE username = 'admin' AND password = '';

这个查询会检查数据库中是否存在用户名为admin且密码为空的用户。

利用优先级进行攻击

攻击者还可以利用AND的优先级高于OR的特性进行攻击。假设攻击者输入如下:

  • 用户名:admin' OR '1'='1

  • 密码:任意值(例如:123456

拼接后的SQL查询如下:

SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = '123456';

由于AND的优先级高于OR,所以实际执行的查询如下:

SELECT * FROM users WHERE (username = 'admin') OR (('1'='1') AND password = '123456');

这意味着:

  1. 首先计算 username = 'admin'

  2. 然后计算 ('1'='1') AND password = '123456'。由于 '1'='1' 总是为真,所以这个表达式简化为 true AND password = '123456',即 password = '123456'

  3. 最后,整个表达式变为 username = 'admin' OR password = '123456'

那么这就意味着,在这种情况下,不管用户输什么进去,只要username能够输对,password不论输什么都能登陆成功。

二、解决SQL注入

使用PreparedStatement接口

PreparedStatementStatement的子接口,它提供了预编译SQL语句的功能,从而可以有效防止SQL注入漏洞。预编译SQL语句的关键在于使用占位符(?)来代替参数部分,这样可以先将SQL语句发送到数据库服务器进行编译,编译后的SQL语句格式是固定的,后续传入的任何值都会作为参数处理,而不会被解释为SQL代码。

步骤和方法

1. 创建PreparedStatement对象

通过Connection接口提供的prepareStatement方法来创建PreparedStatement对象。这个方法需要传入一个SQL语句,其中参数部分用?占位符表示。

Connection conn = // 获取数据库连接
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
2. 向占位符传入值

使用PreparedStatement提供的方法向占位符传入值。这些方法包括setIntsetStringsetXXX等,具体取决于参数的类型。

String username = "admin";
String password = "password123";
pstmt.setString(1, username); // 将第一个占位符替换为username
pstmt.setString(2, password); // 将第二个占位符替换为password
3. 执行SQL语句

根据执行的SQL语句类型,使用executeQueryexecuteUpdate方法来执行查询。

  • executeQuery:用于执行查询语句,返回ResultSet对象。

  • executeUpdate:用于执行增删改语句,返回受影响的行数。

ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
    // 处理查询结果
}

// 或者执行增删改操作
int affectedRows = pstmt.executeUpdate();

示例

假设我们有一个用户登录功能,需要查询数据库中是否存在匹配的用户名和密码。使用PreparedStatement可以安全地实现这一功能。

import java.sql.*;

public class UserLogin {
    public static void main(String[] args) {
        String jdbcURL = "jdbc:mysql://localhost:3306/yourdatabase";
        String username = "root";
        String password = "yourpassword";

        String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
        
        try (Connection conn = DriverManager.getConnection(jdbcURL, username, password);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
             
            String inputUsername = "admin";
            String inputPassword = "password123";
            pstmt.setString(1, inputUsername);
            pstmt.setString(2, inputPassword);
            
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                System.out.println("登录成功!");
            } else {
                System.out.println("用户名或密码错误!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

总结

通过使用PreparedStatement,我们可以有效地防止SQL注入漏洞。预编译SQL语句的关键在于使用占位符(?)来代替参数部分,这样可以先将SQL语句发送到数据库服务器进行编译,编译后的SQL语句格式是固定的,后续传入的任何值都会作为参数处理,而不会被解释为SQL代码。这样可以确保即使用户输入恶意代码,也不会影响数据库的安全性。

相关文章:

  • 已解决IDEA无法输入中文问题(亲测有效)
  • Educational Codeforces Round 174 (Rated for Div. 2)(ABCD)
  • 容器网络(三)- calico网络IPIP模式
  • 深浅拷贝区别,怎么区别使用
  • 最新扣子(Coze)案例教程:全自动DeepSeek 写影评+批量生成 + 发布飞书,提效10 倍!手把手教学,完全免费教程
  • Open WebUI项目源码学习记录(从0开始基于纯CPU环境部署一个网页Chat服务)
  • 解决 ssh connect to host github.com port 22 Connection timed out
  • 重看Spring聚焦BeanDefinition分析和构造
  • LED灯闪烁实验:Simulink应用层开发
  • EtherCAT(四) 从站XML文件描述
  • vite配置scss全局变量
  • 22.4.3.2 TCP/UDP连接信息
  • 深度学习在文本情感分析中的应用
  • java数据结构_优先级队列(堆)_6.2
  • 4. grafana(7.5.17)功能菜单简介
  • 15-最后一个单词的长度
  • 体验用ai做了个python小游戏
  • ECOLOGY流程表单字段由单行文本改成多行文本
  • DeepSeek + Claude 提升效果
  • 当C#邂逅Deepseek, 或.net界面集成deepseek
  • 外交部:中方期待印巴巩固和延续停火势头,避免冲突再起
  • 第1现场 | 印巴停火次日:当地民众逐渐恢复正常生活
  • 农行深圳市分行原副行长王国彪涉嫌严重违纪违法被查
  • 印控克什米尔地区再次传出爆炸声
  • 碧桂园:砸锅卖铁保交房、持续推进保主体,尽快让公司恢复正常经营
  • 印度32座机场暂停民用航班运营,印称在边境多处发现无人机