【Web安全】转义字符注入?转义也会失效的SQL注入

文章目录

⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。

一、明明转义了,为啥还能注入?

先看个场景:程序员为了防SQL注入,老老实实用了PHP官方推荐的转义函数,结果还是被黑客注入了。问题就出在"字符集"这个容易被忽略的细节上------PHP和MySQL用了不同的"翻译手册",转义的保护作用被悄悄抵消了。

二、用代码还原漏洞过程

咱们用一段具体代码,看看黑客是怎么得手的。

1. 有漏洞的代码示例

php 复制代码
<?php
// 连接数据库(PHP默认用GBK字符集处理)
$conn = mysqli_connect('localhost', 'user', 'pass', 'testdb');
if (!$conn) {
    die('连接失败: ' . mysqli_error($conn));
}

// 程序员只告诉MySQL用UTF-8,却没告诉PHP(关键错误!)
mysqli_query($conn, "set names utf8"); 

// 获取用户输入(假设黑客输入:testuser%81' or sleep(3)-- -)
$name = $_GET['name']; 

// 用转义函数处理(PHP以为还在用GBK,按GBK规则转义)
$safe_name = mysqli_real_escape_string($conn, $name); 

// 拼接SQL语句
$sql = "select * from users where name='$safe_name'";
echo "执行的SQL: " . $sql; // 方便查看最终SQL

// 执行查询(这里会触发注入)
$result = mysqli_query($conn, $sql);
mysqli_close($conn);
?>

2. 漏洞一步步爆发

第一步:黑客的输入

黑客在URL里输入:info?name=testuser%81' or sleep(3)-- -

这里的%81是关键,它对应计算机里的字节0x81(十六进制)。在GBK字符集里,0x81属于"双字节字符的前半部分"(可以理解为"半个字")------GBK规定,双字节字符的前半部分范围是0x81-0xFE(就像字典里的"偏旁部首",需要和后面的"笔画"组成完整的字)。

类似的"半个字"还有0xDF(也就是%df)、0x90%90)等,只要在0x81-0xFE范围内,作用都一样,黑客随便选一个就行。

第二步:PHP的转义操作

PHP的mysqli_real_escape_string按默认的GBK规则转义:

  • 输入里的单引号'(对应字节0x27)是特殊字符,转义函数会在它前面加一个反斜杠\(对应字节0x5C),把'变成\'(实际存储的字节是0x5C 0x27)。

这里有个容易误解的点:转义后我们看到的%81\\'里有两个反斜杠\\,但这只是"显示效果"。实际存储的只有一个反斜杠字节0x5C,之所以显示成\\,是因为反斜杠\本身在字符串里是"特殊符号",需要用\\才能正确显示。

简单说:%81'转义后,实际字节是0x81 0x5C 0x27(对应%81\'),但显示时会变成%81\\',方便我们看清"这里有一个反斜杠"。

第三步:MySQL的"错读"

因为程序员用了set names utf8,MySQL会用UTF-8规则解读收到的数据。这时候问题来了:

  • UTF-8对"双字节字符"有自己的规定:前半部分必须在0xC0-0xDF范围内,且后半部分必须≥0x80(比如0xC2 0xA1是有效的UTF-8字符)。
  • 而我们的0x81(前半部分)不在UTF-8的范围内,后面的0x5C(反斜杠,字节值92)也小于0x80,所以0x81 0x5C在UTF-8里是"无效的字符组合"。

MySQL遇到无效组合时,会把它们拆成单个字节:0x81被当成一个无效字符(可能显示成?),0x5C(反斜杠)被单独拎出来------这时候反斜杠原本的"保护作用"(保护单引号不闭合)就没了。

第四步:SQL被注入

最终拼接的SQL变成:
select * from users where name='testuser%81\\' or sleep(3)-- -'

但MySQL用UTF-8解读后,实际效果是:
select * from users where name='testuser?\' or sleep(3)-- -'

这里的单引号'因为失去了反斜杠的保护,直接"打断"了前面的字符串,导致or sleep(3)-- -变成有效的SQL命令(-- -会注释掉后面多余的单引号)。于是MySQL执行sleep(3),页面卡顿3秒,黑客就知道注入成功了。

三、这个漏洞的风险有多大?

  1. 数据泄露:黑客可以通过注入获取数据库里的账号、密码、个人信息等;
  2. 数据篡改:修改、删除数据库中的数据(比如删订单、改余额);
  3. 服务器控制:如果数据库权限高,可能通过注入执行系统命令,控制整个服务器。

更危险的是,它利用了"官方推荐的转义函数",容易让程序员放松警惕,以为代码是安全的。

四、怎么防御?

核心原则:让PHP和MySQL用同一套"翻译手册"(字符集),并从根源上避免拼接SQL。

1. 用set_charset同步字符集(最关键)

不要用mysqli_query("set names utf8"),改用mysqli_set_charset,它会同时告诉PHP和MySQL用相同的字符集:

php 复制代码
// 正确做法:同步字符集
$conn = mysqli_connect('localhost', 'user', 'pass', 'testdb');
mysqli_set_charset($conn, 'utf8'); // 同时更新PHP和MySQL的字符集

这样转义函数和MySQL的解读规则一致,反斜杠不会失效。

2. 用预处理语句(彻底杜绝注入)

最安全的方式是用"预处理语句",把SQL结构和用户数据分开,让黑客的输入永远当不了命令:

php 复制代码
// 预处理示例(推荐!)
$conn = mysqli_connect('localhost', 'user', 'pass', 'testdb');
mysqli_set_charset($conn, 'utf8');

$name = $_GET['name'];
// 准备带占位符的SQL
$stmt = mysqli_prepare($conn, "select * from users where name=?");
// 绑定参数(s表示字符串类型)
mysqli_stmt_bind_param($stmt, 's', $name);
// 执行查询
mysqli_stmt_execute($stmt);

预处理语句里,?会被严格当作数据处理,不管输入什么特殊字符,都不会变成SQL命令。

3. 别用废弃的扩展

mysql_real_escape_string(属于早已废弃的mysql扩展)完全不能用,必须用mysqliPDO扩展。

五、总结

转义函数不是万能的,它的安全依赖于PHP和MySQL的字符集一致。如果两边"翻译错了",哪怕是0x810xDF这样的"半个字",都能让反斜杠的保护失效,导致注入。

同步字符集是基础,预处理语句是王道------这两个做到了,绝大多数SQL注入都能防住。

相关推荐
介一安全1 天前
【Frida Android】基础篇12:Native层hook基础——调用原生函数
android·网络安全·逆向·安全性测试·frida·1024程序员节
m0_738120721 天前
网络安全编程——TCP客户端以及服务端Python实现
python·tcp/ip·安全·web安全·网络安全
白帽子黑客罗哥1 天前
Redis实战深度剖析:高并发场景下的架构设计与性能优化
redis·网络安全·性能优化·高并发·分布式锁·秒杀系统·缓存架构
半路_出家ren1 天前
设计一个学生管理系统的数据库
linux·数据库·sql·mysql·网络安全·数据库管理员
泷羽Sec-静安1 天前
Less-1 GET-Error based-Single quotes-String GET-基于错误-单引号-字符串
前端·css·网络·sql·安全·web安全·less
cai_huaer1 天前
BugKu Web渗透之 文件包含2
web安全·1024程序员节
儒道易行1 天前
【攻防实战】Redis未授权RCE联动metasploit打穿三层内网(上)
数据库·redis·网络安全·缓存
small_white_robot2 天前
vulnerable_docker_containement 靶机
运维·网络·web安全·网络安全·docker·容器
小小小CTFER2 天前
理论题] 2025 年 “技耀泉城” 海右技能人才大赛网络安全知识竞赛题目(二)
算法·安全·web安全