ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python漏洞扫描系统实战:Django+Nmap+Docker构建与避坑

Python漏洞扫描系统实战:Django+Nmap+Docker构建与避坑 简介这份资源是一篇面向初级运维人员与初级网络安全研究者的毕业设计类文档围绕基于Python的漏洞扫描系统展开重点解决中小型网络环境中安全检测门槛高、工具集成难的问题。文档以Django Web框架搭建B/S架构平台借助Docker轻量级虚拟化封装Nmap扫描工具涵盖用户认证、信息管理、漏洞扫描、日志文章与权限管理等模块设计并配有需求分析、逻辑架构与功能模块划分的完整论述。资源包内共1个docx文件约2.18MB内容为系统设计与实现说明结构上从绪论、技术简介到系统分析与设计逐章推进便于读者理解整体方案与实现思路。目前已有345人学习下载适合需要参考漏洞扫描系统设计、学习Django与Docker集成应用或撰写同类课题的读者使用。1. 从一份 docx 标题说起Python 漏洞扫描系统到底在扫什么很多人第一次看到「基于 Python 的漏洞扫描系统」这个标题脑子里浮现的是电影里那种黑底绿字、噼里啪啦滚 IP 的画面。真实情况要朴素得多它本质是一个调度器把 Nmap 这类扫描引擎的输出解析成结构化数据再套上 Web 界面和数据库让「扫了哪些主机、开了哪些端口、对应什么风险」变成可查询、可复现的记录。我在实际项目里最常被问的不是「怎么写扫描器」而是「扫完一堆结果怎么存、怎么展示、怎么不把自己扫崩」。这篇笔记就按这个思路走先讲清系统边界再落到 Django 建表、Nmap 调用、Docker 打包最后把踩过的坑摊开。适合有 Python 基础、想做一个能跑起来的安全工具原型的同学也适合已经写过脚本但没做过完整 Web 系统的人。2. 系统边界与选型为什么是 Python Django Nmap Docker2.1 扫描引擎为什么选 Nmap 而不是自己写 socket自己用 socket 写端口探测不是不行但你要处理超时重传、半开连接、服务指纹识别、操作系统探测这些 Nmap 已经做了二十多年。Nmap 是什么工具一句话网络发现和安全审计的事实标准。它支持-sV版本探测、-O系统识别、-sC默认脚本输出格式有 XML、JSON、grepable 三种。对系统集成来说XML 最稳因为字段层级固定解析不会因为版本升级就崩。我一般这样分工Nmap 负责「发现」Python 负责「编排和解析」Django 负责「存储和展示」。不要让 Django 的请求线程直接去跑 Nmap因为一次全端口扫描可能几分钟到几十分钟Web 请求会超时。正确做法是异步任务队列或者至少用子进程加超时控制。2.2 Django 在这里的角色不是「网站」而是「数据层」Django 执行查询、删除对象这些操作在漏洞扫描系统里对应的是查询某次扫描任务的所有开放端口、删除过期扫描记录、按风险等级过滤结果。Django 的 ORM 让这些操作不用手写 SQL迁移系统让表结构变更可追溯。新手常犯的错是把 Django 当成纯前端框架其实它更适合做「带管理后台的数据中枢」。选 Django 而不是 Flask 的理由很实际自带 admin、自带 ORM、自带用户认证。漏洞扫描系统需要多用户、需要权限隔离、需要后台管理扫描任务这些 Django 开箱即用。Flask 更轻但你要自己拼这些组件对新手不友好。2.3 Docker 解决的是「Nmap 装不上」这个玄学问题Windows 上装 Nmap 经常遇到权限问题Linux 上不同发行版包名不一样macOS 上又涉及 Homebrew 路径。Docker 把这些差异抹平一个镜像里装好 Nmap 和 Python 依赖换台机器docker compose up就能跑。Docker Desktop 安装教程网上很多但要注意 Windows 家庭版需要 WSL2虚拟化没开的话会报virtualisation support wasnt detected这个后面避坑章节细说。提示Docker 镜像里跑 Nmap 需要--cap-addNET_RAW或--privileged否则 SYN 扫描会失败。这是权限边界不是配置错误。3. 用 Django 搭最小可运行骨架建表、建 App、跑迁移3.1 创建项目和扫描专用 App先确保 Python 环境干净。我习惯用 venv不用全局 Python避免 django 版本冲突。# 创建虚拟环境并激活 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装 Django 和 Nmap 的 Python 封装 pip install django python-nmap # 创建项目 django-admin startproject vulnscan cd vulnscan # 创建扫描核心 App python manage.py startapp scanner逻辑说明python-nmap是对 Nmap 命令行的封装它调用系统安装的 nmap 可执行文件所以镜像里必须同时装 nmap 和 python-nmap。参数上startapp scanner生成的是标准 Django App 结构后面所有模型和视图都放这里。3.2 设计扫描结果的数据模型漏洞扫描系统的核心表就三张扫描任务、主机、端口/漏洞。不要一上来就设计十几张表先跑通最小闭环。# scanner/models.py from django.db import models class ScanTask(models.Model): target models.CharField(max_length255) # 目标 IP 或网段 created_at models.DateTimeField(auto_now_addTrue) status models.CharField(max_length20, defaultpending) # pending/running/done/failed def __str__(self): return f{self.target} - {self.status} class Host(models.Model): task models.ForeignKey(ScanTask, on_deletemodels.CASCADE, related_namehosts) ip models.GenericIPAddressField() hostname models.CharField(max_length255, blankTrue) os_match models.CharField(max_length255, blankTrue) class Port(models.Model): host models.ForeignKey(Host, on_deletemodels.CASCADE, related_nameports) port models.IntegerField() protocol models.CharField(max_length10, defaulttcp) state models.CharField(max_length20) # open/closed/filtered service models.CharField(max_length100, blankTrue) version models.CharField(max_length255, blankTrue)逻辑说明on_deletemodels.CASCADE表示删除任务时级联删除主机和端口避免脏数据。related_name让反向查询写成task.hosts.all()比默认的host_set可读。GenericIPAddressField比 CharField 多一层格式校验存 IPv6 也不会崩。参数说明status字段用字符串而不是枚举是为了迁移方便后期要加状态不用改数据库。version字段留 255 长度因为 Nmap 的版本字符串可能很长比如Apache httpd 2.4.41 ((Ubuntu))。3.3 迁移与后台注册python manage.py makemigrations scanner python manage.py migrate python manage.py createsuperuser然后在scanner/admin.py里注册模型这样 Django admin 就能直接看扫描结果from django.contrib import admin from .models import ScanTask, Host, Port admin.site.register(ScanTask) admin.site.register(Host) admin.site.register(Port)逻辑说明Django admin 不是给最终用户用的是给你调试用的。扫描任务跑完进 admin 看数据对不对比写查询语句快得多。等数据模型稳定了再写面向用户的视图。4. 调用 Nmap 并解析结果从命令行到数据库的完整链路4.1 用 python-nmap 执行扫描# scanner/scan_engine.py import nmap def run_scan(target, ports1-1024): nm nmap.PortScanner() # -sV 版本探测-T4 加速--open 只显示开放端口 nm.scan(hoststarget, portsports, arguments-sV -T4 --open) results [] for host in nm.all_hosts(): host_info { ip: host, hostname: nm[host].hostname(), os_match: nm[host].get(osmatch, [{}])[0].get(name, ) if nm[host].get(osmatch) else , ports: [] } for proto in nm[host].all_protocols(): for port in nm[host][proto].keys(): p nm[host][proto][port] host_info[ports].append({ port: port, protocol: proto, state: p[state], service: p.get(name, ), version: f{p.get(product, )} {p.get(version, )}.strip() }) results.append(host_info) return results逻辑说明nmap.PortScanner()每次实例化都会调用系统 nmap所以不要在循环里反复创建。arguments里的-T4是速度模板T0 最慢最隐蔽T4 较快T5 最快但可能丢包。内网扫描用 T4 够了公网目标建议 T2 或 T3避免触发防护。参数说明ports1-1024是常见端口范围全端口是1-65535但全端口扫描很慢建议先扫常见端口再对开放端口做深度探测。--open只返回开放端口减少数据量。4.2 把结果写进 Django 数据库# scanner/tasks.py from .models import ScanTask, Host, Port from .scan_engine import run_scan def execute_scan(task_id): task ScanTask.objects.get(idtask_id) task.status running task.save() try: results run_scan(task.target) for r in results: host Host.objects.create( tasktask, ipr[ip], hostnamer[hostname], os_matchr[os_match] ) for p in r[ports]: Port.objects.create( hosthost, portp[port], protocolp[protocol], statep[state], servicep[service], versionp[version] ) task.status done except Exception as e: task.status failed raise e finally: task.save()逻辑说明try/except/finally保证无论扫描成功还是失败任务状态都会更新。finally里的task.save()是后悔药避免任务卡在 running 状态。实际项目里这个函数应该丢给 Celery 或 RQ 异步执行不要直接在视图里调用。参数说明task_id用整数而不是对象传入是为了兼容异步队列的序列化。如果直接用 Celery任务函数参数必须是可 JSON 序列化的类型。4.3 用 Docker 打包整个环境# Dockerfile FROM python:3.11-slim # 安装 nmapslim 镜像里没有 RUN apt-get update apt-get install -y nmap rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [python, manage.py, runserver, 0.0.0.0:8000]# docker-compose.yml version: 3.8 services: web: build: . ports: - 8000:8000 volumes: - .:/app cap_add: - NET_RAW - NET_ADMIN command: python manage.py runserver 0.0.0.0:8000逻辑说明cap_add是必须的Nmap 的 SYN 扫描需要原始套接字权限。不加的话 Nmap 会自动降级为 TCP connect 扫描速度慢且结果略有差异。volumes挂载当前目录是为了开发时改代码不用重新 build。参数说明python:3.11-slim比alpine兼容性好因为 alpine 用 musl libc某些 Python 包编译会出问题。requirements.txt里至少要有django和python-nmap。5. 避坑与排查那些让我加班到凌晨的翻车现场5.1 Nmap 报权限错误You requested a scan type which requires root privileges现象容器里跑扫描日志显示权限不足扫描结果为空。 原因Docker 默认没有 NET_RAW 能力Nmap 无法创建原始套接字。 解决在docker-compose.yml里加cap_add: [NET_RAW, NET_ADMIN]或者用--privileged启动。生产环境建议用 cap_add不要用 privileged。5.2 Django 迁移时报No module named scanner现象makemigrations找不到 App。 原因settings.py的INSTALLED_APPS里没加scanner。 解决在INSTALLED_APPS列表末尾加scanner,注意逗号。改完再跑makemigrations。5.3 Docker Desktop 启动失败virtualisation support wasnt detected现象Windows 上装完 Docker Desktop启动就报虚拟化未检测到。 原因BIOS 里 Intel VT-x 或 AMD-V 没开或者 Hyper-V 被其他虚拟化软件占用。 解决进 BIOS 开虚拟化Windows 功能里确认 Hyper-V 和「虚拟机平台」已启用。如果装了 VMware先关掉再试。这个坑没有代码能救只能改系统设置。5.4 扫描结果重复写入现象同一个任务跑两次数据库里出现两份主机记录。 原因execute_scan没有做幂等处理重复调用就重复插入。 解决在写入前先Host.objects.filter(tasktask).delete()或者给Host加unique_together (task, ip)约束。我一般用后者让数据库兜底。5.5 扫描大网段时内存暴涨现象扫/24网段时 Python 进程内存飙升。 原因nm.all_hosts()把所有结果一次性加载到内存。 解决改用nm.scan(hoststarget, arguments-sV -T4 --open -oX -)直接输出 XML 流用xml.etree.ElementTree.iterparse逐条解析。或者把网段拆成/28分批扫描。6. 进阶技巧让扫描系统从「能跑」到「好用」6.1 用 Django 的bulk_create把写入速度提上去前面execute_scan里逐条Port.objects.create()扫 1000 个端口就是 1000 次 INSERT。改成批量port_objs [] for p in r[ports]: port_objs.append(Port( hosthost, portp[port], protocolp[protocol], statep[state], servicep[service], versionp[version] )) Port.objects.bulk_create(port_objs, batch_size500)batch_size500是经验值太大容易撞数据库的 SQL 长度限制太小又没效果。实测 1000 条记录从 3 秒降到 0.2 秒。6.2 用 Nmap 脚本做漏洞初筛Nmap 自带vuln脚本类别能查一些已知漏洞nmap --script vuln -sV 192.168.1.1在 Python 里对应arguments-sV --script vuln。注意这个脚本集比较慢而且误报率不低适合做初筛不适合做最终结论。我一般把它和-sC默认脚本分开跑避免一次扫描太久。6.3 扫描任务的异步化从线程到 CeleryDjango 视图里直接调execute_scan会阻塞请求。最小改动是用threading.Threadimport threading from .tasks import execute_scan def start_scan(request, task_id): t threading.Thread(targetexecute_scan, args(task_id,)) t.start() return JsonResponse({status: started})但线程方案在 Django 开发服务器上还行生产环境用 gunicorn 多 worker 时会失控。正经做法是 Celery Redis把execute_scan注册成shared_task视图里调execute_scan.delay(task_id)。Docker 里再加一个 worker 容器和 web 容器共享代码卷。6.4 验证扫描结果是否可信扫完不要直接信。我习惯做三件事第一用nmap -p port ip单独验证某个端口确认不是误报第二对比两次扫描结果如果差异很大可能是网络抖动或目标有防护第三把-sV的版本信息和目标服务的实际 banner 对比比如curl -I http://ip:port看 Server 头是否一致。注意扫描公网目标前确认你有授权。未授权扫描在多数地区是违规行为内网测试也要走审批流程。6.5 一个我常犯的错误早期我总想把所有功能塞进一个 App模型、视图、扫描逻辑全写在一起结果改一处崩三处。后来强制自己拆scanner/models.py只管数据scanner/scan_engine.py只管调 Nmapscanner/tasks.py只管编排。这样换扫描引擎时只改一个文件Django 部分完全不动。这个习惯帮我省了很多返工时间希望帮到你。本文还有配套的精品资源点击获取
返回列表