Python Web漏洞扫描系统:从信息搜集到漏洞检测的完整实现

Python Web漏洞扫描系统:从信息搜集到漏洞检测的完整实现 简介Web安全防护的起点是发现风险渗透测试与漏洞扫描成为企业自查和攻防演练的核心手段。一个完整的扫描流程往往从信息搜集开始涵盖子域名枚举、端口探测、指纹识别与目录爆破这些侦察动作决定了后续漏洞检测的精准度。在技术实现上基于Python生态的Flask框架可快速构建Web管理界面配合Celery异步任务队列处理耗时扫描任务结合SQLAlchemy与SQLite完成结果存储形成一套可复用的工程化方案。针对SQL注入、XSS、目录泄露等经典漏洞插件化检测机制能灵活扩展并生成结构化报告。这类系统适用于小规模资产自查、CTF训练和安全教学在真实业务中也能作为半自动化的漏洞发现工具其架构设计与实现思路为深入学习安全自动化提供了有效参考。1. 项目背景与整体设计思路1.1 为什么选这个题目以及它解决的痛点Web漏洞扫描系统这类题目在毕业设计里算是常青树了原因很简单它的技术栈清晰涉及面广但不失控既能体现Python编程能力、Flask Web开发能力又能展示对网络安全基础知识的掌握程度还特别容易把“工作量”做出来。选题阶段我就确定了一个原则不能只做一个“能跑起来”的CRUD系统而是要有真实的安全测试逻辑在里面这样答辩才有东西可讲。这个系统的核心目标可以拆成两条线一是信息搜集也就是扫描前的资产发现和情报收集二是漏洞扫描也就是对目标Web应用发起检测找出SQL注入、XSS、目录泄露等常见风险点。两条线都围绕一个基于Flask的Web界面展开用户输入目标域名或URL系统自动执行一系列扫描任务最后生成可查看、可导出的报告。它的应用场景很像一个简化版的安全测试平台适合小规模甲方自查、CTF入门训练也适合毕业设计展示完整的工程能力。1.2 技术选型背后的考量Flask、Celery与SQLite的组合技术选型这块我按“毕业设计该有的成熟度”来定而不是一味追求生产级方案。后端框架选Flask而不是Django是因为这个系统的业务逻辑以API为主模板渲染只占一小部分Flask的轻量特性让代码结构更可控单文件能起的服务对新手也友好。前端则用原生HTML、CSS加少量JavaScript配合动态渲染没有引入Vue或React因为扫描任务本身需要轮询结果用AJAX就够了引入重型前端框架反而增加答辩时被追问的风险。任务调度是一个关键点。扫描任务不是瞬时操作端口扫描可能几十秒目录爆破可能几分钟如果直接在Flask的请求处理函数里同步执行请求会被阻塞浏览器一直转圈不说超时后任务状态也丢了。我的方案是用Celery做异步任务队列Broker用Redis。扫描任务提交后立即返回任务ID前端通过轮询接口查询任务状态和结果。这套组合在真实项目和毕业设计里都是非常稳妥的选择也能体现出具备分布式任务处理的思维能力。还有个细节是数据库选型。我用的是SQLite加SQLAlchemy ORM数据库表不多分别是任务表、目标表、漏洞结果表、子域名信息表、端口信息表。SQLite的优点是不需要单独配置数据库服务答辩演示时不用折腾环境直接跑起来就是完整系统。如果后续真要扩展SQLAlchemy切到MySQL也就是改一行URI的事。1.3 系统模块划分与整体架构这个系统的模块划分遵循“数据流驱动”的原则。用户输入目标URL后系统按以下路径工作信息搜集模块接收目标进行子域名枚举、IP解析、端口存活检测、Web指纹识别、目录/文件爆破搜集结果存入数据库漏洞扫描模块基于搜集到的Web指纹和URL列表对探测到的每个Web服务执行漏洞检测插件扫描结果汇总生成报告。架构上我分了三层任务接入层Flask路由和API、业务逻辑层扫描引擎、插件加载器、报告生成器、数据存储层数据库和文件缓存。这里要特别强调一件事扫描引擎和Web层一定要解耦。我第一版代码把扫描逻辑直接写在路由函数里面结果一跑长任务Flask就堵死后来才改成独立模块加Celery异步化。所以做这个项目的同学架构设计千万别省否则后期返工成本极高。2. 信息搜集模块扫描之前的侦察工作2.1 子域名枚举与IP信息收集信息搜集模块是整个系统数据的第一来源如果这步做不好后续漏洞扫描就是无源之水。子域名枚举我实现了两种方式基于字典的暴力枚举和基于搜索引擎接口的被动收集。字典暴力枚举很好理解就是构造一个常见子域名词典admin、test、oa、api、mail这类高频前缀然后对每个候选域名发起DNS解析请求解析成功则说明该子域名存在。这里要注意DNS请求的频率控制如果纯单线程跑几百个域名速度很慢且容易触发目标DNS服务器的速率限制。我用了Python的concurrent.futures.ThreadPoolExecutor线程数控制在20实测几百条记录的枚举在一两分钟内能完成。解析库用的是dnspython的resolver设置超时2秒遇到超时或NXDOMAIN直接跳过。被动收集这块我调用了两个公开接口一个是通过搜索引擎的site语法查询子域另一个是通过证书透明度日志平台查询。后者效果好很多因为CA签发的证书里经常会带上所有子域拿回来正则提取即可。这部分代码量不大但答辩时是个亮点因为证书透明度是近几年行业里比较前沿的信息搜集思路。IP信息收集相对简单域名解析拿到IP后用IP归属查询接口标记地理位置和运营商再尝试判断该IP是否属于CDN节点。判断CDN有个土办法对同一个域名用不同公共DNS服务器分别解析如果返回多个不同IP且在不同网段大概率是CDN。这个逻辑在真实扫描中很重要因为如果目标挂在CDN后面直接扫描源站IP才有意义扫CDN节点容易误判。不过考虑到目标规模我最终只做了提示没有做太深。2.2 端口探测与Web指纹识别端口探测这步我用了自己实现的TCP Connect扫描器。原理非常直接用socket模块去连接目标的每个端口如果连接成功说明端口是开放的。扫描范围是常用的前1000个端口包括80、443、22、21、3306、6379、27017等。要注意的是TCP Connect扫描的缺点是会留下完整的连接日志容易被IDS发现但这是一个教学和演示性质的项目不需要那么隐蔽反倒是完整握手的好处是结果可靠不容易误判。针对开放端口上的服务我做了服务指纹识别通过发送特定探测数据包比对返回的banner信息判断服务类型和版本。比如连上MySQL 3306端口服务端通常会返回版本号的欢迎信息连上Nginx的80端口HTTP响应头里的Server字段会直接暴露版本。正则匹配这部分我维护了一个指纹库跑通一个加一个目前大概有几十条常见规则。Web指纹识别则是通过HTTP响应头、HTML元信息、Cookie特征、特定路径文件是否可访问来综合判断站点用的什么CMS或框架比如WordPress的wp-content路径、ThinkPHP的X-Powered-By头、Spring Boot的Whitelabel Error Page特征等。指纹识别对后续漏洞扫描的意义非常大。知道目标跑的是Apache还是Nginx是直接决定用哪个漏洞检测插件的关键信息避免发一些驴唇不对马嘴的无效请求。所以我在扫描引擎设计里指纹识别结果会作为漏洞插件的触发条件之一。2.3 目录扫描与爬虫模块的实现细节目录扫描用的是经典的字典爆破思路。提前准备一份常见的目录字典包含admin目录、backup目录、.git泄露目录、配置文件路径.env、config.php.bak、上传目录等然后逐个发HTTP请求通过状态码判断目录是否存在。这里有个经验状态码不等于一切。很多站点对不存在的路径会返回200加一个自定义的404页面反而对存在的目录返回403不允许列出或302需要登录跳转。所以判断逻辑不能只看200要把403、302也当作“目录可能存在”来处理编码时我设置了一个状态码白名单记录逻辑宁可产生少量误报也不能漏掉真实的敏感路径。爬虫模块承担的是URL收集工作。我从目标首页开始用requests加BeautifulSoup解析页面中的a标签和form标签提取链接并去重遇到相对路径则拼接为绝对URL。爬取深度控制为2层单页链接上限设为200条避免爬到外网或跑成无底洞。再通过robots.txt解析允许爬取的路径作为URL集合的补充。爬到的链接会统一交给漏洞扫描模块去做参数检测这比单独扫描域名根路径覆盖面大得多因为它能挖到实际带参数的请求SQL注入和XSS往往就藏在这些参数里。3. 漏洞扫描模块核心检测逻辑与插件化设计3.1 为什么用插件化架构扩展性与可维护性漏洞扫描模块我做了插件化设计这是整个系统里最能体现工程能力的地方。每一个漏洞检测逻辑都是一个独立的Python类统一继承自一个基类。基类定义了execute方法、目标URL属性、漏洞等级属性和结果上报方法子类只需要实现自己的检测逻辑。扫描引擎加载插件时使用Python的pkgutil遍历插件目录自动发现并注册所有可用插件。这样设计的好处很明显。第一新增漏洞检测能力不需要修改原有代码直接在插件目录放一个新文件就行系统重启后自动加载第二单个插件出问题时不会影响其他插件的执行引擎在调用插件时会捕获异常并记录日志第三答辩时可以这样描述“高内聚低耦合的设计模式”非常加分。插件分类方面我按照漏洞类型分成了注入类、跨站类、信息泄露类、配置缺陷类和其它类五个包。每个插件实现了两个方法check_target预处理检测目标是否适用于当前插件execute执行具体检测。比如SQL注入插件会先检测URL中是否存在参数没有参数就直接跳过从而节省扫描时间。3.2 四种经典漏洞的检测实现SQL注入、XSS、目录泄露、敏感文件SQL注入检测我采用了三种策略组合。第一是错误回显检测构造单引号和双引号闭合字符请求后检查响应中是否出现SQL语法错误特征比如”MySQL”、”You have an error in your SQL syntax”、”sqlite”、”ORA-“等一旦命中基本可以确认数据库类型和注入点位置。第二是布尔盲注检测构造true和false两个条件请求比如and 11与and 12比较两个响应的页面长度和内容差异如果结果差异稳定就判定参数存在布尔注入。第三是时间盲注检测构造sleep函数MySQL环境响应时间显著延长的则判定存在时间盲注。时间盲注的判定阈值设为5秒实测要特别注意网络波动带来的误报至少要对比三次取平均值再做判断。XSS检测的思路类似将payload参数值注入到目标URL的参数中请求后检查响应中是否原样回显payload内容。这里要区分反射型和存储型扫描系统主要做反射型检测。payload集合我准备了多组包括script标签、svg标签、img错误事件等覆盖常见过滤绕过场景。检测回显时用的是模糊匹配把和标签包裹的核心payload部分去掉两端的引号再匹配因为很多站点会做引号转义。目录遍历检测比较简单在URL路径部分加上../的循环组合去请求比如/etc/passwd、/windows/win.ini这类系统文件路径如果响应内容里出现了root:或boot loader等标志性内容则判定存在路径穿越漏洞。敏感文件泄露检测则是基于一份文件路径字典逐个探测常见备份文件、版本控制目录、配置文件。3.3 结果入库与扫描报告生成漏洞检测的每个命中结果都会被写入漏洞结果表记录目标URL、漏洞类型、漏洞等级、请求参数、响应摘要、检测时间和修复建议。漏洞等级我分了高、中、低三档SQL注入和命令执行属于高危XSS和目录遍历属于中危Web指纹信息泄露和服务器组件版本过旧属于低危。报告生成模块我做了两种格式网页版和PDF版。网页版是一个只读的详情页面展示扫描概览、漏洞列表和修复建议适合在线查看PDF版用模板渲染加HTML转PDF来实现适合下载保存和答辩展示。报告里除了漏洞清单还会生成统计图表用ECharts绘制漏洞等级分布饼图和趋势图这个视觉呈现对答辩演示是很大的加分项。4. 实操过程从环境搭建到完整扫描复现4.1 环境准备与依赖安装如果你要复现这个项目我建议按以下环境来准备Python版本用3.8以上太低的版本对类型标注和异步支持不友好太高比如3.13个别库可能还没适配。操作系统Windows或Linux都行Linux下跑Celery更顺畅Windows下注意Celery需要额外配置事件循环。核心依赖如下Flask 2.xWeb服务框架Celery 5.x异步任务队列RedisCelery的Broker和BackendrequestsHTTP请求BeautifulSoup4HTML解析dnspythonDNS解析SQLAlchemyORM安装命令很简单pip install flask celery redis requests beautifulsoup4 dnspython sqlalchemyRedis需要单独安装并启动Windows下可以使用Memurai替代或者用Docker跑一个Redis容器Linux下直接apt或yum安装。这里有个小坑Celery 5.x的Broker URL配置如果格式不对会出现连接拒绝的报错检查一下redis://localhost:6379/0这样的写法是否和你本机Redis端口一致即可。4.2 核心代码结构与关键配置说明项目目录结构分为以下几个核心模块app.pyFlask应用入口注册路由和APItasks.pyCelery任务定义扫描任务的入口函数scanner/扫描引擎包collect/信息搜集模块子域名、端口、指纹、目录vuln/漏洞检测插件包engine.py插件加载和调度逻辑models.py数据库模型定义templates/前端页面模板reports/生成报告的目录Flask路由部分我设计了五个主要接口。第一个是提交扫描任务接收目标URL和扫描选项返回任务ID第二个是查询任务状态第三个是查询任务结果第四个是获取历史扫描记录第五个是导出报告。这些都是REST风格接口前端用AJAX轮询调用。端口扫描模块的代码核心是socket连接def scan_port(host, port): sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1.0) result sock.connect_ex((host, port)) sock.close() return result 0这个函数返回True表示端口开放。注意settimeout设成1秒如果网络状况差可以放宽到2秒但建议不要太久因为大规模扫描时每个端口都等很久是灾难。4.3 配置扫描任务与前端联动提交扫描这个流程我简单说一下实现逻辑。前端页面上有一个表单用户填入目标URL勾选需要执行的扫描类型子域名、端口、目录、漏洞检测可以分别开关点击提交后JavaScript用fetch发送POST请求到/api/scan接口。后端接口函数启动一个Celery异步任务立即返回JSON格式的任务ID。前端轮询部分的JavaScript代码大致是这样的async function checkStatus(taskId) { while (true) { const response await fetch(/api/task/${taskId}); const data await response.json(); updateProgress(data); if (data.status SUCCESS || data.status FAILURE) { window.location.href /result/${taskId}; break; } await new Promise(resolve setTimeout(resolve, 2000)); } }每两秒请求一次任务状态通过Celery的result对象获取进度百分比和中间结果前端用进度条展示。这一步是用户体验的关键如果不用异步任务用户面对一个卡死的页面会焦虑答辩时观感也不好。4.4 实测过程一个本地测试站点的完整扫描我在本机搭了一个基于DVWA的测试环境来验证整个系统。提交http://localhost:8080/DVWA作为目标后系统流程如下信息搜集阶段端口扫描发现8080端口开放指纹识别判断为Apache/PHP架构目录扫描发现DVWA的登录页和几个PHP文件。漏洞扫描阶段引擎针对搜索功能页面和输入参数执行SQL注入检测成功在参数id上触发时间盲注的延时特征XSS检测在反射点上复现了script payload回显。整个过程大概跑了三分钟结果页面显示高危漏洞1个、中危漏洞2个、低危信息若干。实测下来系统基本达到了设计预期。但同时也暴露出几个问题比如对JS渲染的页面爬虫无能为力目录扫描的字典还不够全对WAF的识别能力有限。这些既是不足也是后续可以继续优化的方向。5. 常见问题与排查技巧实录5.1 扫描任务排队不执行或卡住的排查方法Celery任务提交后一直没有worker执行这是新手最容易踩的坑。首先确认Celery worker有没有启动启动命令是celery -A tasks worker --loglevelinfo启动后日志会显示ready状态。如果worker起来了但任务还是不进队列检查Redis连接使用redis-cli ping确认Redis进程正常。还有一种情况是tasks模块导入失败导致worker启动失败但日志被刷过去了没注意到建议用--logleveldebug启动一次看看完整的导入堆栈。还有一种更隐蔽的问题Windows环境下Celery 5.x不支持在交互式命令行里用默认的prefork并发模式需要指定--poolsolo参数否则启动时直接报错。5.2 扫描误报率太高结果判定逻辑怎么调优误报主要集中在布尔盲注和时间盲注上。布尔盲注的误报原因往往是把正常动态页面的内容差异误判成了注入差异。例如参数值改变会触发不同的SQL查询结果两个响应页面本身就存在差异跟注入无关。解决办法是在判定逻辑中加入基线请求先请求一次不带任何注入payload的原始URL记录基线指纹再对比注入条件下的响应差异只有基线一致、注入请求才出现差异的情况才判定为注入。时间盲注的误报来源是网络抖动。我的改进方案是对同一参数连续测试三次sleep请求三次的平均耗时达标才认定存在注入同时加入本地延迟基线校准每次测试前先请求一个静态资源测量网络往返延迟再从总耗时中扣除。实际操作中这个措施能把时间盲注的误报率降低一半以上。5.3 反爬与请求频率限制会不会影响扫描结果很多目标站点有反爬策略比如对单IP请求频率做限制触发后返回403或验证码页面这种情况下扫描器拿到的响应全是拦截页指纹识别和漏洞检测都会失灵。对策是给扫描器加请求间隔配置默认每次请求间隔0.2秒匹配到验证码特征时自动退避到1秒。同时设置User-Agent池每次请求随机选择一个避免同一个UA高频出现。但这里要特别提醒你配置的请求频率越低单次扫描耗时越长一个端口扫描加目录爆破加漏洞检测的完整流程可能从几分钟拉长到半小时。所以扫描配置里务必提供“快速模式”和“全量模式”两档毕业设计演示时用快速模式展示流程自己做测试时用全量模式这样体验更好。6. 毕业设计答辩经验与后续扩展方向6.1 演示时最容易出彩的三个环节答辩演示这块我总结出几个经验。第一个要让评委看到真实的安全检测效果提前准备一个有漏洞的测试站点DVWA或自己写一个带SQL注入和XSS的简单PHP页面现场扫描让评委亲眼看到漏洞被识别出来的过程而不是空口说“我们系统的检测率很高”。第二个是展示报告的可视化。报告里的漏洞等级分布饼图和详细列表配上实际的请求和响应摘要能直观体现系统把完整的取证闭环做出来了。第三个是聊架构设计。被问到“你的系统如何扩展新的漏洞检测能力”时现场演示往插件目录里添加一个新文件重启后系统自动识别并运行这个插件这个从代码到演示的闭环会显得你真正理解了可扩展性的含义。6.2 后续演进从教学演示走向半自动化运维这个系统如果想继续深入有几个方向可以考虑。一是加入POC验证模块检测到的疑似漏洞不直接判定而是调用相应的验证脚本确认漏洞是否真实可利用这需要额外维护一个POC库依赖关系和管理会复杂一些但能大幅降低误报率。二是引入WebSocket替换轮询机制前端实时推送扫描进度体验能再上一个台阶。三是支持批量目标和计划任务对接企业资产管理系统从手动输入目标演进到自动发现、定期扫描的SaaS服务架构。还有一个比较实用的小改进是配置管理把目标URL、扫描选项、字典路径等统一放到配置文件里用Flask的配置系统加载而不是散落在各模块的硬编码里这样后续维护会省很多事。系统跑过几百次之后你会发现维护成本最高的不是扫描逻辑而是字典库和指纹库这些数据资产的持续更新才是把这个项目做成产品的最关键一环。6.3 常见问题速查表我把开发过程中确认过的最实用的几条经验整理成了表格方便你对照排查现象可能原因解决方案任务提交后无响应Celery worker未启动执行celery -A tasks worker --loglevelinfoworker启动报错Windows下prefork模式不支持加--poolsolo参数端口扫描结果全为空目标防火墙拦截TCP连接检查本机与目标网络连通性确认端口实际状态时间盲注误报网络延迟波动大增加基线延迟校准单参数测试三次取均值爬虫只拿到首页站点是JS渲染应用升级为无头浏览器渲染或接受当前限制Redis内存持续增长任务结果长时间保留设置result_expires参数定期清理过期结果总体来看这个项目的核心价值不在于它检测了多少种漏洞而在于它完整覆盖了从信息搜集、漏洞发现到报告生成的整个安全测试流程技术栈选型合理、架构清晰、可迁移性高。无论你是拿它当作毕业设计还是想在此基础上继续深挖安全自动化方向这套骨架都能支撑住你的扩展需求。最后分享一个我在实际开发中的体会安全扫描器和普通业务系统最大的区别在于扫描器的输出永远是不可信的每个检测结果都必须能回溯到原始请求和响应否则无法说服任何人。所以在开发过程中所有模块都带上了日志记录每次请求响应都落盘起初觉得麻烦后来发现这是排查问题的救命稻草。做安全方向的工具可审计性比性能更重要这个理念希望你从一开始就放在心上。本文还有配套的精品资源点击获取