☰
Django自动化漏洞扫描系统源码解析与二次开发实战
2026/9/29 19:43:36 网站建设 项目流程

简介:这是一套面向网络安全初学者与渗透测试人员的Web漏洞扫描与安全评估系统源码,基于Python与Django开发,用于对Web应用进行自动化深度扫描与风险发现。系统集成爬虫引擎与自定义规则库,可遍历页面链接、模拟攻击行为,并支持按需扩展扫描规则,同时提供任务管理、结果查看与评估报告生成界面。压缩包共202个文件,约1.16MB,以118个py源码文件为核心,辅以20个html模板、9个js与7个css前端资源,另含sql建表脚本、dic字典、sqlite3数据库及使用说明文档,结构完整便于二次开发。目前已有91人学习下载。读者可从中获取一套可运行的漏洞扫描项目,理解爬虫调度、规则匹配与报告输出的实现思路,并参考其模块化设计进行功能扩展或集成到自有安全测试流程中。

1. 从一份 Django 漏洞扫描系统源码说起:它能替你省掉哪些手工活

很多做 Web 安全的同行都有过这种体验:甲方丢过来一个站,要求两天内出一份安全评估报告,你打开 Burp 挂上代理,一边点功能一边记请求,扫完还得手动整理漏洞清单、补上复现步骤和修复建议。真正耗时间的不是发现漏洞,而是把发现过程标准化、把结果整理成能交付的文档。这份基于 Python 与 Django 构建的自动化 Web 应用漏洞扫描与安全检测系统,瞄准的正是这段重复劳动——它把爬虫引擎、漏洞检测逻辑、自定义规则库和 Web 管理界面打包成一个可部署的完整项目,你拿到手就能跑起来,对目标站点做一轮深度扫描并输出结构化结果。

它适合三类人:一是刚接触 Web 安全、想通过读源码理解扫描器工作原理的 Python 学习者;二是需要给内部系统做定期安全自查的运维或后端开发;三是手里有检测需求、想基于现成框架二次开发自己规则的安全从业者。整套系统用 Django 做后端与展示层,爬虫负责页面发现和表单识别,规则库决定检测哪些漏洞类型,三者解耦,改起来不牵一发动全身。下面按「先跑通、再拆解、后避坑」的顺序,把这份源码包从部署到二次开发讲透。

2. 环境搭建与项目启动:把 Django 扫描器在本机跑起来

拿到一份 Django 项目源码,第一件事不是急着读代码,而是先让它在本机跑起来,确认依赖完整、数据库能建、页面能开。这一步跑通,后面读代码才有参照物。这份系统的技术栈是 Python + Django,常见做法是配 MySQL 或 SQLite,爬虫部分依赖 requests 和 BeautifulSoup 这类库。下面按顺序走一遍。

2.1 Python 与 Django 版本选择

Django 对 Python 版本有硬性要求,选错版本会在pip install阶段就报错。这份项目正文没有写明具体版本号,我一般会先看requirements.txt或settings.py里的写法来判断。稳妥起见,用 Python 3.8~3.10 配 Django 3.2 LTS 是兼容性最好的组合,Django 3.2 是长期支持版,第三方库适配也最全。

# 查看本机 Python 版本,建议 3.8 以上 python3 --version # 创建独立虚拟环境,避免污染全局包 python3 -m venv venv # 激活虚拟环境(Linux/macOS) source venv/bin/activate # 激活虚拟环境(Windows) venv\Scripts\activate # 安装 Django,指定 LTS 版本 pip install django==3.2.20 # 安装爬虫与解析依赖 pip install requests beautifulsoup4 lxml

这里几个参数值得说清楚。python3 -m venv venv创建的是一个隔离目录,里面有自己的site-packages,装什么库都不会影响系统 Python,这是避免「装了一堆库结果互相冲突」的标准做法。django==3.2.20用双等号锁定小版本,防止pip自动拉到不兼容的新版。lxml是 BeautifulSoup 的高性能解析器,比默认的html.parser快不少,爬虫解析大量页面时差别明显。

提示:如果pip install lxml在 Windows 上编译失败,直接装预编译轮子pip install lxml --only-binary :all:,省去配编译环境的麻烦。

2.2 数据库配置与迁移

Django 默认用 SQLite,开箱即用,适合本地跑通和演示。如果要做成多人使用的扫描平台,换成 MySQL 更稳。配置集中在settings.py的DATABASES段。

# settings.py 数据库配置片段 DATABASES = { 'default': { # 本地快速验证用 sqlite3,生产环境换 mysql 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # 若改用 MySQL,替换为下面这段 # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.mysql', # 'NAME': 'vulnscan', # 数据库名 # 'USER': 'root', # 用户名 # 'PASSWORD': 'your_pass', # 密码 # 'HOST': '127.0.0.1', # 数据库地址 # 'PORT': '3306', # 端口 # 'OPTIONS': {'charset': 'utf8mb4'}, # 支持中文和特殊字符 # } # }

ENGINE决定用哪个数据库后端,SQLite 不需要额外服务,文件即数据库,适合先跑通。OPTIONS里的utf8mb4很关键,扫描结果里经常出现中文路径或特殊符号,用默认字符集可能写入报错。改完配置后执行迁移,Django 会根据模型文件自动建表。

# 生成迁移文件,检测模型变化 python manage.py makemigrations # 执行迁移,真正在数据库建表 python manage.py migrate # 创建后台管理员账号,用于登录管理界面 python manage.py createsuperuser

makemigrations只生成描述变更的 Python 文件,不动数据库;migrate才真正执行 SQL。两步分开是为了让你在改表结构前能 review 迁移文件,避免误操作。createsuperuser会让你输入用户名、邮箱和密码,这个账号用来登录 Django 自带的后台,也是扫描任务管理的入口。

2.3 启动服务与首次访问

数据库建好后,直接起开发服务器验证。

# 启动开发服务器,0.0.0.0 允许局域网访问 python manage.py runserver 0.0.0.0:8000

0.0.0.0:8000表示监听所有网卡的 8000 端口,同网段的其他机器也能访问,方便你把扫描器部署在一台机器上、从另一台发起测试。如果只想本机访问,用默认的python manage.py runserver即可。浏览器打开http://127.0.0.1:8000,能看到登录页或首页,说明项目骨架已经跑通。这一步如果报ModuleNotFoundError,基本是依赖没装全,对照requirements.txt逐个补;如果报数据库连接错误,回头检查settings.py的账号密码和数据库服务状态。

3. 爬虫引擎与规则库:扫描逻辑是怎么串起来的

项目跑起来只是第一步,真正决定这套系统好不好用的是它的扫描内核。这份源码把「爬虫发现目标」和「规则匹配漏洞」拆成两个独立环节,理解这个分工,你才知道该改哪里、加什么。下面从爬虫工作流和规则库结构两个角度拆。

3.1 爬虫引擎的页面发现与表单识别

爬虫的任务不是简单地把页面抓下来,而是尽可能完整地枚举出可访问的 URL 和可提交的表单,因为漏洞往往藏在参数和输入点里。常见做法是从一个种子 URL 出发,解析页面里的<a>标签提取新链接,解析<form>标签提取提交地址、方法和字段,然后递归下去,直到没有新链接或达到深度上限。

import requests from bs4 import BeautifulSoup from urllib.parse import urljoin, urlparse def crawl(start_url, max_depth=3): """从起始 URL 出发,广度优先抓取同域链接和表单""" visited = set() # 已访问 URL,防止死循环 queue = [(start_url, 0)] # (url, 当前深度) results = [] # 收集到的页面与表单信息 while queue: url, depth = queue.pop(0) if url in visited or depth > max_depth: continue visited.add(url) try: # 设置超时,避免卡在无响应页面 resp = requests.get(url, timeout=5) resp.encoding = resp.apparent_encoding except requests.RequestException: continue # 单个页面失败不影响整体 soup = BeautifulSoup(resp.text, 'lxml') forms = [] for form in soup.find_all('form'): forms.append({ 'action': urljoin(url, form.get('action', '')), 'method': form.get('method', 'get').lower(), 'inputs': [i.get('name') for i in form.find_all('input') if i.get('name')], }) results.append({'url': url, 'forms': forms}) # 提取同域链接,加入队列 for a in soup.find_all('a', href=True): link = urljoin(url, a['href']) if urlparse(link).netloc == urlparse(start_url).netloc: queue.append((link, depth + 1)) return results

这段代码有几个参数直接决定扫描效果。max_depth=3控制爬取深度,太浅会漏页面,太深会指数级膨胀,实际项目里通常做成可配置项。timeout=5是单请求超时,没有它,遇到一个挂起的页面整个扫描就卡死。urlparse(link).netloc == urlparse(start_url).netloc这行做同域限制,只爬目标站自己的链接,避免爬虫跑到外站去,这既是效率考虑也是合规边界。resp.apparent_encoding让 requests 根据内容猜编码,比默认的 ISO-8859-1 靠谱,中文页面不会乱码。

注意:爬虫的请求频率要控制,生产环境里加个time.sleep(0.5)或令牌桶限速,否则容易把目标站打挂,也可能触发对方的防护机制。

3.2 自定义规则库的结构与扩展方式

规则库是这套系统的灵魂,它决定「扫什么漏洞、怎么判断」。常见做法是把每条规则写成一个独立配置,包含匹配位置、匹配模式、危害等级和修复建议。规则和扫描引擎分离,加新规则不用改引擎代码。

字段含义示例
rule_id规则唯一编号R001
name漏洞名称SQL 注入
location检测位置url 参数 / 表单字段 / 响应头
pattern匹配特征报错关键字、正则
severity危害等级高 / 中 / 低
suggestion修复建议参数化查询
# rules.py 规则库示例结构 RULES = [ { 'rule_id': 'R001', 'name': 'SQL 注入疑似', 'location': 'param', 'payload': "' OR '1'='1", # 注入测试载荷 'pattern': r'(SQL syntax|mysql_fetch|ORA-\d{5})', # 响应特征 'severity': 'high', 'suggestion': '使用参数化查询,过滤用户输入', }, { 'rule_id': 'R002', 'name': '反射型 XSS 疑似', 'location': 'param', 'payload': '<script>alert(1)</script>', 'pattern': r'<script>alert\(1\)</script>', # 载荷原样回显 'severity': 'medium', 'suggestion': '对输出做 HTML 实体编码', }, ]

payload是发出去的测试内容,pattern是判断漏洞是否存在的响应特征。SQL 注入规则里,如果响应里出现数据库报错关键字,就说明载荷可能被带进了 SQL 语句。XSS 规则更直接,载荷原样出现在响应里就判定为反射型。severity用于结果排序和报告分级,suggestion直接进报告,省去你手写修复建议的时间。扩展时只要往RULES列表里加字典,引擎遍历执行即可,这是这套设计最实用的地方。

3.3 扫描任务调度与结果落库

爬虫拿到 URL 和表单,规则库提供检测逻辑,中间需要一个调度层把两者串起来,并把结果写进数据库供页面展示。Django 的模型层天然适合干这个。

# models.py 扫描结果模型 from django.db import models class ScanTask(models.Model): target = models.URLField() # 扫描目标 created_at = models.DateTimeField(auto_now_add=True) status = models.CharField(max_length=20, default='pending') # 任务状态 class VulnResult(models.Model): task = models.ForeignKey(ScanTask, on_delete=models.CASCADE) # 关联任务 rule_id = models.CharField(max_length=20) url = models.URLField() severity = models.CharField(max_length=10) detail = models.TextField()

ForeignKey把漏洞结果挂到扫描任务下,一个任务对应多条结果,删任务时结果级联删除,不会留孤儿数据。status字段跟踪任务进度,前端可以轮询展示「进行中 / 已完成」。调度时遍历爬虫结果,对每个参数位置套用规则库里的 payload,发请求、匹配 pattern、命中就写一条VulnResult。这套流程跑通后,你在页面上点一次扫描,后台就自动完成发现、检测、入库、展示的闭环。

4. 避坑与常见问题:跑扫描器时最容易翻车的几处

源码能跑起来不代表能稳定出结果,实际部署和扫描过程中有几类问题反复出现。下面按「现象 → 原因 → 解决」整理,都是我在类似项目里踩过的。

现象一:扫描任务一直卡在「进行中」,页面不更新。原因通常是爬虫遇到死循环或某个请求没有超时,线程被挂住。递归爬取时如果 URL 规范化没做好,/a和/a/会被当成两个页面反复入队。 解决:给所有requests请求加timeout,URL 入队前做归一化(去掉末尾斜杠、统一小写),并设置最大访问数量上限,超过就停。

现象二:明明有漏洞,扫描结果却是空的。原因多半是规则里的pattern写得太死,或者目标站返回的编码和预期不一致,导致匹配失败。比如报错信息被 HTML 实体转义了,正则匹配不到。 解决:匹配前先对响应做一次html.unescape,正则尽量用宽松的关键字而非完整句子,并在调试时把响应原文打印出来对照。

现象三:扫描把目标站拖慢甚至打挂。原因是并发太高或没有限速,短时间发大量请求。 解决:加请求间隔,把并发数压到个位数,生产环境扫描前先和站点负责人确认时间窗口。这既是技术问题也是职业素养问题。

现象四:Django 迁移时报「No changes detected」。原因是你改了模型但 app 没注册到INSTALLED_APPS,Django 根本没扫描到你的模型文件。 解决:检查settings.py的INSTALLED_APPS,把应用名加进去,再重新makemigrations。

现象五:中文扫描结果在页面上显示成乱码。原因是数据库字符集或响应编码没处理对。 解决:MySQL 用utf8mb4,Python 侧统一用resp.apparent_encoding解码,模板输出时确认没有二次转义。

提示:调试扫描逻辑时,先用一个你自己搭的测试站(比如 DVWA 这类靶场)验证规则命中率,别直接拿生产站试,出了误报或漏报都不好收场。

5. 二次开发与验证:把规则库改成你自己的检测清单

跑通默认规则之后,这套系统真正的价值在于你能按自己的需求扩展。我一般会先做一件事:拿一个已知有漏洞的靶场跑一遍,看哪些规则命中了、哪些漏了,然后针对性补规则。下面说两个具体技巧。

第一个是给规则加「验证请求」字段,降低误报。默认规则只发一次 payload 看响应特征,容易把正常报错当成注入。改进做法是命中后再发一次无害请求做对比,两次响应差异明显才判定为漏洞。

def verify_sql_injection(url, param, payload): """对比正常请求与注入请求的响应差异,降低误报""" normal = requests.get(url, params={param: 'normal_value'}, timeout=5) attack = requests.get(url, params={param: payload}, timeout=5) # 正常请求无报错、注入请求有报错,才判定命中 error_kw = ['SQL syntax', 'mysql_fetch', 'ORA-'] normal_has_err = any(k in normal.text for k in error_kw) attack_has_err = any(k in attack.text for k in error_kw) return attack_has_err and not normal_has_err

normal请求用无害值,attack请求用注入载荷,只有「正常无报错、注入有报错」才返回 True。这个对比逻辑能把大部分因为页面本身带报错关键字导致的误报过滤掉。参数error_kw按目标数据库类型调整,MySQL、Oracle、SQL Server 的报错关键字各不相同。

第二个技巧是用 Django 的管理命令批量跑扫描,而不是只在页面上点。这样能挂到定时任务里做定期自查。

# 自定义管理命令,批量扫描配置好的目标列表 python manage.py scan_targets --file targets.txt --output report.json

--file指定目标清单,--output指定结果导出路径,方便接入 CI 或定时脚本。写这个命令时,把扫描逻辑封装成可复用函数,命令里只做参数解析和循环调用,逻辑和入口分离,后面改起来不牵连。

验证规则是否有效,最直接的办法是准备一组「已知答案」的测试用例:哪些 URL 有注入、哪些有 XSS,跑完看命中率。命中率低就调 pattern,误报高就加验证请求。这套流程走顺之后,你手里就不只是一个下载来的源码包,而是一份能持续维护的检测清单。从那以后我每次拿到新的扫描类项目,都强制先用靶场跑一轮基线,确认规则命中率再上真实目标,这个习惯帮我省掉了不少返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询