☰
Django漏洞扫描系统源码实战:从环境搭建到规则落库与避坑指南
2026/10/27 6:44:35 网站建设 项目流程

简介:本资源为基于Django框架与Python实现的漏洞扫描系统完整源码包,面向计算机、信息安全、数据科学等专业的在校学生、教师及企业员工,适用于课程设计、期末大作业、毕业设计及初期项目立项演示。项目涵盖主机漏洞扫描、Web网页漏洞扫描、数据库管理、用户交互、漏洞报告、用户管理、日志记录与修复评估八大模块,支持端口扫描、服务识别、XSS与SQL注入检测、报告导出PDF/HTML等功能,并附详细项目说明。压缩包共441个文件,以146个py源码、68个html模板、42个js脚本及scss、css、less样式文件为主,另含sql数据库脚本、json配置、bat启动脚本与图片资源,整体约8.46MB,目录结构清晰便于按模块检索。目前已有320人学习下载,适合需要完整网络安全项目实战、二次开发或撰写论文的读者参考借鉴。

1. 从一份 Django 漏洞扫描系统源码说起:它到底能扫什么、不能扫什么

拿到「基于Django框架+python实现的漏洞扫描系统源码+sql数据库+详细项目说明.zip」这类资源的人,通常有两种心态:一种是刚学完 Django 想找个能写进简历的项目,另一种是手上有一批内网资产,想搭个轻量工具先跑起来看看。这两种诉求差别很大,但都能从同一套代码里各取所需。这个系统的本质,是把「目标发现 → 端口/服务探测 → 规则匹配 → 结果入库 → Web 展示」这条链路用 Python 串起来,再用 Django 做一层管理界面和任务调度入口。它能解决的是资产清点、常见弱口令和已知组件版本比对这类重复劳动,不能替代专业漏扫引擎做深度利用验证。适合有 Python 基础、懂一点 HTTP 和数据库、想自己掌控扫描逻辑的运维或安全方向从业者。下面按「先跑通、再改规则、最后避坑」的顺序拆开讲。

2. 环境搭建与项目骨架:把 Django 和 SQL 数据库先跑起来

2.1 为什么选 Django 而不是 Flask 做扫描系统的壳

扫描系统本身的计算逻辑跟 Web 框架关系不大,真正决定选型的是「任务管理、结果存储、权限、页面展示」这几块。Django 自带 ORM、Admin、迁移和用户体系,一个python manage.py migrate就能把 SQL 数据库表结构建好,省掉大量手写 CRUD 的时间。常见做法是用 Django 做控制台,扫描核心写成独立的 Python 模块,通过 Celery 或线程池异步调用,避免请求阻塞。如果换成 Flask,路由和模板要自己拼,Admin 也得额外接,对新手不友好。所以这套源码选 Django 是合理的,重点在于你要理解它的分层:views负责接收扫描任务,models负责落库,scanner目录才是真正的扫描逻辑。

2.2 依赖安装与数据库配置的最小步骤

先确认 Python 版本,建议 3.8 以上,然后建虚拟环境。数据库方面,源码通常默认 SQLite 方便演示,但生产环境建议换 MySQL 或 PostgreSQL,因为扫描结果写入频繁,SQLite 的并发写会锁表。

# 创建并激活虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖,requirements.txt 一般包含 Django、requests、pymysql 等 pip install -r requirements.txt # 初始化数据库表结构 python manage.py makemigrations python manage.py migrate # 创建后台管理员,用于登录 Django Admin 查看扫描结果 python manage.py createsuperuser # 启动开发服务器 python manage.py runserver 0.0.0.0:8000

上面每一步都有明确目的:makemigrations根据models.py生成建表语句,migrate真正执行到数据库,createsuperuser让你能进/admin看数据。如果migrate报错,九成是数据库连接配置不对,去settings.py的DATABASES段核对NAME、USER、PASSWORD、HOST、PORT。用 MySQL 时还要先pip install mysqlclient或在__init__.py里加pymysql.install_as_MySQLdb()。

2.3 扫描核心模块的目录结构与调用关系

一套能用的源码,目录一般长这样:scanner/下放port_scan.py、web_scan.py、poc_check.py,tasks.py负责调度,models.py里定义ScanTask、ScanResult两张主表。调用链是:前端提交目标 → view 创建ScanTask记录 → 异步任务读取目标 → 调用具体扫描函数 → 结果写ScanResult→ 页面轮询展示。理解这条链,你改规则时才知道该动哪个文件。比如想加一个针对某中间件弱口令的检测,就在poc_check.py里加函数,在tasks.py里注册调用,不用碰前端。

# scanner/port_scan.py 简化示例 import socket def scan_port(host, port, timeout=1): """返回 True 表示端口开放,False 表示关闭或超时""" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(timeout) # 超时设太大会拖慢整体扫描 try: s.connect((host, port)) return True except (socket.timeout, ConnectionRefusedError): return False finally: s.close()

这段代码的关键参数是timeout。内网可以设 0.5 到 1 秒,公网目标建议 2 到 3 秒,否则大量超时会让你误判端口关闭。socket.AF_INET表示 IPv4,如果要支持 IPv6 得换AF_INET6。实际项目中不要单线程循环扫全端口,用concurrent.futures.ThreadPoolExecutor控制并发数,一般 100 到 200 线程比较稳,再高容易被目标防火墙拉黑。

3. 扫描规则与 SQL 数据库落库:让结果可查、可复现

3.1 规则文件怎么写:从端口指纹到 Web 特征匹配

扫描系统的价值不在端口开放本身,而在「开放之后判断出这是什么服务、什么版本、有没有已知问题」。常见做法是维护一份规则表,端口指纹用 banner 抓取加正则,Web 特征用请求特定路径看返回头或 body 关键字。规则建议单独放rules/目录,用 JSON 或 YAML 存,方便不改代码就能扩充。

# scanner/web_scan.py 特征匹配片段 import requests def check_web_feature(url, keyword, timeout=5): """请求目标 URL,判断响应体中是否包含指定关键字""" headers = {"User-Agent": "Mozilla/5.0 (compatible; ScanBot/1.0)"} try: resp = requests.get(url, headers=headers, timeout=timeout, verify=False) return keyword.lower() in resp.text.lower() except requests.RequestException: return False

verify=False是为了跳过自签名证书报错,但会带来警告,生产环境建议把目标证书指纹存下来做校验。timeout设 5 秒是折中值,太短会漏掉响应慢的页面,太长会拖垮任务队列。User-Agent不要用默认的 python-requests,很多 WAF 会直接拦截,伪装成常见浏览器能提高存活率。

3.2 扫描结果如何写进 SQL 数据库

结果落库是这套系统区别于「一次性脚本」的核心。表设计一般分两层:ScanTask记录一次任务的目标、开始时间、状态;ScanResult记录每条发现,外键关联任务。这样你能按任务查历史,也能按目标查趋势。

# 在 tasks.py 中保存结果的典型写法 from .models import ScanTask, ScanResult def save_finding(task_id, host, port, vuln_type, detail): task = ScanTask.objects.get(id=task_id) ScanResult.objects.create( task=task, host=host, port=port, vuln_type=vuln_type, # 如 "weak_password"、"outdated_component" detail=detail, # 存原始证据,方便复现 created_at=timezone.now() )

vuln_type建议用固定枚举值,不要写自由文本,否则后期统计和去重会很痛苦。detail字段存原始响应片段或命令行输出,这是你复现问题的「后悔药」。如果一次任务结果上万条,逐条create会慢,改用bulk_create批量插入,每 500 条提交一次。

3.3 用 Django ORM 做结果查询与去重

扫描跑多了,同一目标同一问题会反复出现。去重逻辑可以放在入库前,也可以放在查询时。常见做法是给(host, port, vuln_type)建联合唯一索引,入库用update_or_create,这样重复扫描只更新时间不新增记录。

# 去重入库示例 ScanResult.objects.update_or_create( task=task, host=host, port=port, vuln_type=vuln_type, defaults={"detail": detail, "created_at": timezone.now()} )

注意update_or_create在高并发下可能触发竞态,稳妥做法是数据库层加唯一约束,捕获IntegrityError后重试。查询时用ScanResult.objects.filter(vuln_type="weak_password").values("host").distinct()快速拉出受影响主机列表,比在 Python 里循环去重快得多。

4. 避坑与排查:扫描系统最容易翻车的五个地方

4.1 扫描结果全是「端口关闭」,但目标明明活着

现象:任务跑完,开放端口数为零,手动 telnet 却能通。原因通常是并发线程过高导致本机文件描述符耗尽,或者timeout设得太短,SYN 包还没回来就判超时。解决:把并发降到 50 到 100,timeout提到 2 秒,并在 Linux 下用ulimit -n 65535提高句柄上限。另外确认没有把目标写成域名而 DNS 解析失败,先ping一下。

4.2 数据库写入报「database is locked」

现象:用 SQLite 时,扫描任务一多就报锁表。原因是 SQLite 同一时刻只允许一个写操作,而扫描结果是高频写入。解决:换 MySQL 或 PostgreSQL,或者在 Django 配置里加OPTIONS: {"timeout": 20}延长等待,同时把结果写入改成批量提交,减少事务次数。长期跑扫描的系统不要用 SQLite 做生产库。

4.3 规则匹配误报率高,把正常页面当成漏洞

现象:报告里一堆「疑似漏洞」,人工一看全是误报。原因是关键字匹配太宽,比如用error去匹配响应体,正常页面也有这个词。解决:规则要加「与」条件,比如同时命中特定路径、特定状态码和特定关键字才算;并且把匹配到的原始响应存进detail,方便人工复核。规则上线前先拿正常业务系统跑一遍,看误报量能不能接受。

4.4 扫描任务卡在「运行中」不结束

现象:任务状态一直是 running,页面不刷新结果。原因是异步任务抛异常没被捕获,或者线程池没设置超时。解决:在任务入口加try/except并记录日志,给每个目标设总超时,比如单目标不超过 300 秒。Django 侧可以用celery的soft_time_limit强制中断。排查时先看日志文件,再看数据库里任务的状态字段有没有被更新。

4.5 换数据库后中文乱码或时间不对

现象:从 SQLite 换到 MySQL,中文变成问号,时间差 8 小时。原因是字符集没设utf8mb4,时区没设Asia/Shanghai。解决:建库时指定CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,Django 配置里TIME_ZONE = "Asia/Shanghai"、USE_TZ = False。如果已经建好库,用ALTER DATABASE和ALTER TABLE改字符集,时间字段用CONVERT_TZ修正。

5. 进阶技巧:把扫描系统从「能跑」推到「敢用」

5.1 用任务队列替代线程池,让扫描可暂停可重试

线程池的缺点是进程一重启任务就丢,也没法优雅暂停。进阶做法是引入 Celery + Redis,每个目标是一个独立 task,支持retry和revoke。配置上把CELERY_TASK_ACKS_LATE = True,保证 worker 崩溃后任务能重新投递。这样你可以在页面上加「暂停」「重跑失败项」按钮,实用性提升一个档次。

# celery 任务定义示例 from celery import shared_task @shared_task(bind=True, max_retries=3, default_retry_delay=10) def scan_target(self, task_id, host): try: run_scan(task_id, host) except Exception as exc: raise self.retry(exc=exc) # 失败自动重试,最多 3 次

max_retries=3是经验值,网络抖动重试三次基本能覆盖;default_retry_delay=10避免瞬间重试打爆目标。注意重试要幂等,也就是同一目标重复扫描不会产生重复记录,这靠前面说的唯一索引保证。

5.2 用「扫描指纹」判断结果是否可信

同一个漏洞,不同扫描方式置信度不同。可以在ScanResult里加一个confidence字段,端口开放给 0.5,banner 匹配给 0.7,实际请求验证给 0.9。展示时按置信度排序,低置信度的折叠起来。这样报告给出去不会因为一堆误报失去信任。验证方法很简单:挑置信度最低的十条人工复核,如果误报超过三条,说明规则该收紧。

检测方式置信度建议适用场景
端口开放0.5资产清点
Banner 关键字0.7服务识别
版本号比对0.8已知组件
实际请求验证0.9弱口令、未授权

5.3 我踩过的坑和现在的习惯

早期我图快,把并发开到 500,结果本机网络先瘫了,扫描报告全是超时,白白跑了一晚上。后来固定「内网 100 并发、公网 30 并发」,再没出过这种事。另一个习惯是每次改规则先拿三个已知目标做回归,确认误报和漏报都没恶化再全量跑。这套 Django 漏洞扫描系统源码本身不复杂,值不值得投入,取决于你愿不愿意持续维护规则库——代码一周能跑通,规则却要长期打磨。希望帮到你。

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

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

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

立即咨询