【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注入都能防住。

相关推荐
网安INF3 小时前
【论文阅读】-《Sparse Adversarial Attack via Perturbation Factorization》
论文阅读·人工智能·计算机视觉·网络安全·黑盒攻击
lingggggaaaa3 小时前
小迪安全v2023学习笔记(九十七天)—— 云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行
java·笔记·学习·安全·网络安全·云原生·kubernetes
余防5 小时前
代码审计
安全·web安全·网络安全
Whoami!7 小时前
4-8〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸命令注入漏洞
网络安全·信息安全·oscp·命令注入攻击
盛满暮色 风止何安9 小时前
网络安全设备 防火墙
服务器·网络·网络协议·计算机网络·安全·web安全·网络安全
合作小小程序员小小店19 小时前
Web渗透之一句话木马
web安全·网络安全·安全威胁分析·安全架构·安全性测试
white-persist20 小时前
Burp Suite模拟器抓包全攻略
前端·网络·安全·web安全·notepad++·原型模式
网安小白的进阶之路1 天前
A模块 系统与网络安全 第四门课 弹性交换网络-3
网络·安全·web安全
源文雨1 天前
MacOS 下 Warp ping 局域网设备报错 ping: sendto: No route to host 的解决方法
运维·网络协议·安全·macos·网络安全·ping