详解SQL注入问题

一、代码漏洞根源

核心危险代码:

复制代码
// 直接拼接用户输入拼接SQL语句
String sql="select * from password where username='"+username+"'and password='"+password+"'";

使用 Statement + 字符串拼接 SQL ,用户输入的内容会直接拼入 SQL 语句,数据库会执行输入里的 SQL 逻辑,造成注入攻击。

二、注入攻击演示

1. 恶意输入

  • 用户名输入:

    1111

  • 密码输入:

    1' or '1' ='1

2. 拼接后最终执行 SQL,恒成立

复制代码
select * from password where username='1111'and password='1' or '1' ='1'

输出:

三、SQL 能登录成功的核心逻辑

数据库是这样计算的:

复制代码
where (条件A  and  条件B)  or  条件C
  • 条件 A :username='1111'
  • 条件 B :password='1'
  • 条件 C :'1'='1' → 永远成立!

最终结果:

复制代码
假 and 假  or  真
= 假 or 真
= 真

只要有一个条件成立,整个 WHERE 就成立! → 直接查到数据 → 登录成功!

本来想让数据库验证:

复制代码
用户名正确 并且 密码正确

结果被用户改成了:

复制代码
(用户名正确 并且 密码正确) 或者 1=1

1=1 永远是对的,所以不管用户名密码是什么,都能登录!


五、SQL 注入原理

用户输入的内容里带 SQL 语法,直接破坏了原本的查询逻辑,可以实现绕过密码登录。

  1. 前端用户输入带有 SQL 语法的特殊字符
  2. 后端无过滤,直接把输入拼入完整 SQL
  3. MySQL 识别拼接后的完整 SQL 并执行恶意逻辑
  4. 实现越权查询、篡改、删除数据

六、高危注入危害输入

  • 篡改全部数据
  • 直接删除数据表

七、解决方案(杜绝 SQL 注入)

  1. 放弃 Statement,使用 PreparedStatement 预编译对象
  2. 使用 ? 作为占位符替代字符串拼接
  3. 预编译会把用户输入全部当成普通文本,不会解析执行 SQL 语法

安全修复代码

复制代码
package com.qcby.sql;

import java.sql.*;
import java.util.Scanner;

public class LoginUtil {
    public static void main(String[] args) throws Exception{
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入用户名");
        String username=scanner.nextLine();
        System.out.println("请输入密码");
        String password=scanner.nextLine();
        safeLogin(username,password);
    }

    public static void safeLogin(String username,String pwd) throws Exception{
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url="你的数据库";
        String user="***";
        String password="****";
        Connection connection= DriverManager.getConnection(url,user,password);

        // 使用占位符,禁止字符串拼接
        String sql = "select * from password where username=? and password=?";
        PreparedStatement pstmt = connection.prepareStatement(sql);
        // 给占位符赋值
        pstmt.setString(1,username);
        pstmt.setString(2,pwd);

        ResultSet set=pstmt.executeQuery();
        if(set.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        set.close();
        pstmt.close();
        connection.close();
    }
}
相关推荐
2301_780789662 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
ClickHouseDB2 小时前
ClickHouse Cloud 与 Snowflake 实时性价比对比:CostBench 测试中的 412 倍差距来
运维·数据库·系统架构
m0_639906942 小时前
Redis入门|五种数据结构、使用场景、持久化RDB&AOF
数据结构·数据库·redis
时间售卖铺3 小时前
触发器与函数实战:MySQL高效编程秘诀
运维·数据库·mysql·云原生
qetfw3 小时前
UOS MariaDB 数据库:安装、最小权限与备份验证
linux·数据库·mariadb·uos
星融元asterfusion4 小时前
工业网络升级实战:100G 双轨 Leaf-Spine 架构破解高并发出货网络瓶颈
网络·架构·spine
Da Da 泓4 小时前
五子棋 Web 端测试用例报告
前端·网络·websocket·网络协议·测试用例·项目
数智园区合作社4 小时前
问数平台怎么把同一个指标锁成一个数
大数据·数据库·人工智能·ai
云和数据.ChenGuang5 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
lbb 小魔仙5 小时前
Windows搭建PaddleOCR+飞书Webhook自动打卡通知机器人:识别、推送与远程触发完整教程
数据库·人工智能·prometheus·时序数据库