
简介这是一份面向初级运维人员与网络安全研究者的毕业设计类文档围绕基于Python的漏洞扫描系统展开重点讲解如何借助Django Web框架与Docker容器技术搭建低学习成本的B/S架构扫描平台。内容涵盖需求分析、系统总体与逻辑架构设计以及用户认证、用户信息管理、漏洞扫描、日志文章、权限管理等模块的划分并涉及Nmap工具集成、漏洞检测与报告生成等核心功能适合作为课程设计、毕设选题或入门安全实践的参考方案。资源包共1个docx文件约2.18MB为完整论文文档含摘要、目录与章节正文便于直接阅读与二次整理。目前已有345人学习下载可帮助读者快速理解系统设计思路、模块划分方式与关键技术选型为动手实现类似平台提供结构化的参考依据。1. 从一份 docx 标题说起Python 漏洞扫描系统到底在扫什么很多人第一次看到「基于Python的漏洞扫描系统的设计与实现.docx」这个标题脑子里浮现的是电影里那种黑底绿字、噼里啪啦滚动的界面。但真落到工程里它其实是一套很朴素的流水线资产发现 → 端口与服务识别 → 规则匹配 → 结果落库 → 报告输出。Python 在这里不是主角光环而是胶水——把 Nmap 这类成熟扫描器、Django 这类 Web 框架、Docker 这类部署环境粘成一个能跑、能看、能复现的系统。它适合谁适合手上有几台内网机器、想定期摸清开放端口和已知弱配置的运维或安全初学者也适合想拿一个完整项目练 Django Docker 全链路的开发者。它不适合谁不适合指望它替代商业漏扫去做合规测评的人——规则库的深度和误报控制是这类自研系统最容易翻车的地方。这篇笔记就按「先跑通最小闭环再补规则和部署」的顺序把这条流水线拆开讲清楚参数怎么设、坑在哪都落到具体命令上。2. 系统骨架怎么搭Django 做控制台Nmap 做扫描引擎2.1 为什么是 Django Nmap 这个组合选型这件事先想清楚系统里谁干活。扫描的脏活累活交给 Nmap它成熟、跨平台、有-oX这种结构化输出省得自己写 SYN 扫描还得处理原始套接字权限。控制层用 Django是因为它自带 ORM、Admin 和模板任务表、结果表、报告页几乎不用从零写django-admin startproject之后就能看到一个能登录的后台。有人会问为什么不用 Flask小项目 Flask 更轻但漏扫系统天然有「任务、资产、漏洞、报告」四张核心表和多角色查看需求Django 的 ORM 迁移和内置权限能省掉大量样板代码。热词里频繁出现的django rbac、django创建app本质就是在解决「谁能看哪些扫描结果」这个问题。至于 Docker它解决的是另一个痛点Nmap 在 Windows 上装起来麻烦nmap下载windows搜出来的安装包版本参差用容器把扫描器和 Web 服务一起打包换台机器docker compose up就能复现这才是它真正的价值。2.2 用 Docker 把运行环境一次装好先解决环境别一上来就写代码。下面这份 compose 文件把 Django 应用、MySQL 和 Redis 串起来Redis 用来做扫描任务的队列避免 Web 请求被长时间扫描阻塞。# docker-compose.yml services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: vulnscan ports: - 3306:3306 volumes: - db_data:/var/lib/mysql redis: image: redis:7-alpine ports: - 6379:6379 web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/app ports: - 8000:8000 depends_on: - db - redis volumes: db_data:逻辑说明db用 MySQL 8.0 存扫描结果redis做任务队列web挂载当前目录方便改代码即时生效。参数上MYSQL_ROOT_PASSWORD生产环境必须换成强密码并从环境变量注入这里写死只为本地跑通。depends_on只保证启动顺序不保证 MySQL 已经能接受连接所以 Django 侧要加连接重试否则第一次migrate大概率报连接被拒。配套的 Dockerfile 里装 Nmap 是关键一步FROM python:3.11-slim RUN apt-get update apt-get install -y nmap rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . .apt-get install -y nmap让容器内自带扫描器requirements.txt里至少要有django、mysqlclient、redis、celery。用国内镜像源是因为默认源在容器里拉包经常超时这是血泪经验不是可选项。2.3 建表资产、任务、漏洞三张核心表数据模型决定了后面报告能出成什么样。核心就三张表别一上来设计十几张先跑通再拆。# scanner/models.py from django.db import models class Asset(models.Model): ip models.GenericIPAddressField(uniqueTrue) hostname models.CharField(max_length255, blankTrue) created_at models.DateTimeField(auto_now_addTrue) class ScanTask(models.Model): target models.CharField(max_length255) # 支持 192.168.1.0/24 status models.CharField(max_length20, defaultpending) created_at models.DateTimeField(auto_now_addTrue) class Finding(models.Model): task models.ForeignKey(ScanTask, on_deletemodels.CASCADE) asset models.ForeignKey(Asset, on_deletemodels.CASCADE) port models.IntegerField() service models.CharField(max_length100, blankTrue) severity models.CharField(max_length10, defaultinfo) detail models.TextField(blankTrue)target用 CharField 而不是 IPField是因为要支持 CIDR 网段192.168.184.1/24这种写法 IPField 存不下。Finding外键挂到ScanTask上并设on_deleteCASCADE删任务时结果一起清掉避免脏数据。severity先给默认值info后面规则匹配时再覆盖成low/medium/high。建完模型执行python manage.py makemigrations python manage.py migrate表就落好了。3. 扫描引擎落地Nmap 命令怎么调、结果怎么解析3.1 活跃主机探测与端口扫描的命令组合扫描分两步走先探活再扫端口能省掉大量对不存在主机的无效扫描。探活用nmap -sn 192.168.184.1/24-sn表示只做 ping 扫描不扫端口输出里带Host is up的就是活着的机器。这一步在容器里跑要注意普通用户没有原始套接字权限时-sn会退化成 TCP 连接探测结果依然可用只是慢一点。端口扫描用nmap -sV -T4 -p- --open -oX result.xml target。逐个参数说清楚-sV做服务版本识别这是后面匹配漏洞规则的基础-T4是速度模板内网可以用公网或老旧设备上-T4容易触发丢包稳妥点降到-T3-p-扫全部 65535 个端口耗时明显如果只关心常见服务可以换成-p 1-1000--open只输出开放端口减少解析噪音-oX输出 XML这是给程序读的关键别用普通文本输出再正则去抠那是自找麻烦。在 Django 里调用它用subprocess起进程注意超时和并发控制# scanner/engine.py import subprocess from xml.etree import ElementTree def run_nmap(target, timeout600): cmd [nmap, -sV, -T4, -p-, --open, -oX, -, target] try: proc subprocess.run(cmd, capture_outputTrue, textTrue, timeouttimeout) except subprocess.TimeoutExpired: return None, scan timeout if proc.returncode ! 0: return None, proc.stderr return proc.stdout, None def parse_nmap_xml(xml_text): findings [] root ElementTree.fromstring(xml_text) for host in root.findall(host): addr host.find(address[addrtypeipv4]) if addr is None: continue ip addr.get(addr) for port in host.findall(.//port): state port.find(state) if state is None or state.get(state) ! open: continue svc port.find(service) findings.append({ ip: ip, port: int(port.get(portid)), service: svc.get(name, ) if svc is not None else , product: svc.get(product, ) if svc is not None else , version: svc.get(version, ) if svc is not None else , }) return findings-oX -把 XML 直接输出到标准输出省去写临时文件再读的步骤容器里文件权限问题也一并绕开。timeout600是给全端口扫描留的余量扫一个 C 段全端口可能远超这个数实际项目里应该按目标数量动态放大或者拆成多个子任务。解析部分只取stateopen的端口product和version字段是后面做版本比对的关键别丢。3.2 把扫描结果写进数据库并做规则匹配解析出来的字典列表要落库同时做一轮规则匹配。规则先别搞复杂用一张表存「服务名 版本区间 风险描述」就够起步。# scanner/tasks.py from .models import Asset, ScanTask, Finding from .engine import run_nmap, parse_nmap_xml RISK_RULES [ {service: ssh, max_version: 7.4, severity: high, detail: SSH 版本过旧存在已知弱加密套件风险}, {service: mysql, max_version: 5.7, severity: medium, detail: MySQL 版本偏低建议升级并检查空口令账户}, ] def execute_scan(task_id): task ScanTask.objects.get(idtask_id) task.status running task.save() xml_text, err run_nmap(task.target) if err: task.status failed task.save() return for item in parse_nmap_xml(xml_text): asset, _ Asset.objects.get_or_create(ipitem[ip]) severity, detail info, for rule in RISK_RULES: if rule[service] in item[service] and item[version] rule[max_version]: severity, detail rule[severity], rule[detail] break Finding.objects.create( tasktask, assetasset, portitem[port], serviceitem[service], severityseverity, detaildetail, ) task.status done task.save()get_or_create保证同一 IP 不会重复建资产记录。规则匹配这里用字符串比较版本号只适合7.4这种简单格式遇到8.0.32-0ubuntu这种带后缀的会出错后面第 5 章会讲怎么处理。severity默认info命中规则才升级这样报告里能区分「只是开放了端口」和「确实有风险」。3.3 用 Celery 把扫描从 Web 请求里拆出去全端口扫描动辄几分钟放在视图函数里同步执行浏览器早就超时了。用 Celery 把execute_scan丢进队列视图只负责创建任务并返回任务 ID。# scanner/views.py from celery import shared_task from django.http import JsonResponse from .models import ScanTask from .tasks import execute_scan shared_task def async_scan(task_id): execute_scan(task_id) def create_scan(request): target request.POST.get(target) task ScanTask.objects.create(targettarget) async_scan.delay(task.id) return JsonResponse({task_id: task.id, status: pending})async_scan.delay把任务推给 RedisCelery worker 在另一个进程里消费。启动 worker 用celery -A yourproject worker -l info注意 worker 容器里同样要装 Nmap否则任务一跑就报nmap: command not found。前端想实时看进度热词里提到的django websocket是一种做法但起步阶段用轮询/api/task/id/查status字段更简单别过早引入 WebSocket 增加调试成本。4. 避坑与排查这套系统最容易翻车的五个地方4.1 容器里 Nmap 报权限不足现象任务状态一直是failed日志里出现Couldnt open a raw socket或Operation not permitted。原因-sV在部分场景下需要原始套接字权限而容器默认以非 root 用户运行或者宿主机没给NET_RAW能力。解决在 compose 的web服务下加cap_add: [NET_RAW, NET_ADMIN]或者临时用user: root跑通再收紧。生产环境更推荐加能力而不是直接给 root。4.2 MySQL 容器起来了但 Django 连不上现象docker compose up后 web 容器反复重启报Cant connect to MySQL server。原因depends_on只管启动顺序MySQL 初始化要几十秒这期间 Django 的migrate已经失败退出。解决在启动命令前加等待脚本比如while ! nc -z db 3306; do sleep 2; done或者用docker compose的healthcheck配合condition: service_healthy。这是新手最容易卡住的一步别怀疑代码。4.3 全端口扫描把目标设备扫挂现象扫描进行到一半目标交换机或老旧打印机离线。原因-T4加-p-在低性能设备上产生大量并发连接触发设备自我保护。解决内网设备扫描降到-T2或-T3并把-p-换成--top-ports 1000先覆盖高频端口。对生产网段扫描前务必确认有授权这不是技术问题而是流程问题。4.4 版本号字符串比较导致规则误判现象MySQL 8.0.32 被规则判成低于 5.7误报 medium 风险。原因8.0.32 5.7在字符串比较下为 True因为逐字符比8大于5之前先比了长度逻辑。解决把版本号按.拆成整数元组再比较写一个parse_version函数遇到非数字后缀就截断。规则匹配是漏扫系统的核心版本比较写错整个报告的可信度就没了。4.5 扫描结果里出现大量重复资产现象同一个 IP 在Asset表里出现多条记录。原因get_or_create的查询条件没命中常见于 IP 字段存了带空格或大小写不一致的值。解决入库前对 IP 做strip()和格式校验GenericIPAddressField本身会规范化但如果从 XML 解析时带了多余字符就会绕过。加一条唯一约束让数据库兜底。5. 让报告能看从原始结果到可读输出的最后一公里系统跑通之后真正决定它有没有人用的是报告。原始 XML 没人看得把Finding表渲染成按资产分组、按严重级别排序的页面。Django 模板里用{% regroup %}按资产分组严重级别用颜色区分high标红、medium标黄、info灰显。这一步不需要额外依赖Admin 后台其实就能看但给非技术同事看还是单独做一个只读页面更友好。进阶一点的做法是给每个Finding加一个「修复建议」字段规则命中时一起写进去。比如 SSH 版本过旧就提示「升级 OpenSSH 到 8.0 以上并禁用密码登录」。这个字段不用很精确但能让报告从「列问题」变成「给动作」价值差一个量级。验证系统是否可靠我一般用三步先扫127.0.0.1确认能识别本机开放端口再扫一台已知跑着 MySQL 5.7 的测试机看规则是否命中最后扫一个不存在的网段确认任务能正常结束而不是卡死。这三步过了基本功能就稳了。有个习惯我保持了挺久每次改完规则先拿历史扫描结果回放一遍看新增规则会不会把之前的info全刷成high。规则库膨胀之后误报比漏报更消耗信任。这套系统值不值得做取决于你是否愿意持续维护规则而不是一次性写完代码就丢那。希望帮到你。本文还有配套的精品资源点击获取