ARTICLE DETAIL

资讯详情

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

Django漏洞扫描系统源码解析:环境搭建、数据库导入与实战部署

Django漏洞扫描系统源码解析:环境搭建、数据库导入与实战部署 简介基于Django框架与Python实现的漏洞扫描系统完整源码包配套SQL数据库和详细项目说明适用于计算机、信息安全、数据科学与大数据、人工智能等专业的课程设计、期末大作业或毕业设计。系统按模块化设计覆盖主机扫描主机发现、端口扫描、服务识别与Web漏洞扫描SQL注入、XSS、CSRF等并包含用户管理、扫描配置、漏洞报告、日志记录和修复评估等完整功能可作为网络安全综合实践项目学习。包内含441个文件以146个Python源码、68个HTML模板、42个JavaScript脚本为主体辅以scss/css样式、SQL数据脚本、配置文件和文档说明压缩包约8.46MB目录结构清晰便于按模块快速定位。目前已有320人学习下载。项目代码经过验证且提供详细说明从环境准备到运行常见问题均有覆盖既适合新手入门理解Django项目搭建和漏洞扫描实现思路也可在此基础上二次开发扩展其他检测功能适合作为毕业设计或课程设计演示项目。1. 拿到这套Django漏洞扫描系统源码第一件事不是跑起来如果你刚下载到“基于Django框架python实现的漏洞扫描系统源码sql数据库详细项目说明.zip”大概率是两种人一种是安全测试方向的学生想找个能改的Web系统练手另一种是运维或开发想快速搭一个内部漏洞扫描平台。这个包的核心价值在于它把「扫描任务管理」「漏洞指纹匹配」「结果入库」串成了一个Django项目还附带SQL数据库文件和项目说明。也就是说你拿到的不只是一堆散落的Python脚本而是一套有数据库、有后台、有任务管理的完整可运行工程。但正因为它是“源码包”直接双击跑往往翻车——依赖缺、数据库版本不对、Django版本兼容问题这些坑我在第一次跑类似项目时就踩了一遍。所以这篇笔记我想按一线实操的顺序帮你把这个zip拆明白怎么搭环境、怎么导数据库、扫描逻辑写在哪儿、跑起来后哪些参数必须调以及常见的翻车点。适合能跟着命令走的人也适合想把它改成自己工具的熟手。2. 拆解项目依赖与目录Django版本、数据库驱动、静态文件三件套拿到zip先解压别急着双击manage.py。先看目录结构一个典型的Django扫描项目会分成这几块manage.py、scan_project/配置目录、scanner/扫描应用、templates/、static/以及一个.sql数据库文件和requirements.txt。如果压缩包里有项目说明.pdf或readme.txt先打开它——我见过不少人在没看说明的情况下直接装依赖结果卡在数据库路径上。2.1 requirements.txt 里的依赖怎么读别一股脑安装打开requirements.txt常见内容类似这样Django3.2,4.0 requests2.25 sqlparse0.4.1 python-nmap1.5.1 celery5.2 redis4.2 django-crontab0.7.1这里的版本范围很重要。Django 3.2 和 Django 4.x 在路由写法、时区设置上都有差异如果源码里的urls.py用的是url()函数那它多半是Django 2.x或3.x时期写的如果用的是path()那3.x、4.x都能跑。我一般会先按 requirements 里的版本装避免直接用最新版Django导致django.urls报错。安装时用虚拟环境别直接怼到系统Python里python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install -r requirements.txt参数说明-r表示读取整个依赖文件。如果你本机已经装过Django建议先pip freeze | grep -i django确认版本。常见的坑是python-nmap需要系统里有nmap命令否则运行时会报nmap not found。这个依赖的作用是调用nmap做端口扫描后面会细说。另外如果依赖里有celery说明它用了异步任务队列那还需要Redis别漏了。2.2 manage.py 与 settings.py 的启动前检查确认依赖装好后进入项目配置目录打开settings.py。重点看三处INSTALLED_APPS、DATABASES、TIME_ZONE。INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, ... scanner, # 扫描应用 rest_framework, # 如果做API ] DATABASES { default: { ENGINE: django.db.backends.sqlite3, NAME: BASE_DIR / db.sqlite3, } }如果ENGINE是django.db.backends.sqlite3那恭喜你最省事。如果是mysql那你要么有MySQL服务要么得改成SQLite。这里我一般会建议本地复现先改成SQLite等项目跑通再换MySQL否则你还要处理mysqlclient编译报错。TIME_ZONE建议改成Asia/Shanghai否则扫描结果里的时间比北京时间晚8小时排查问题时容易怀疑人生。启动前还要检查ALLOWED_HOSTS。如果为空或没配置Django会拒绝非localhost请求。做本地调试可以改成这样ALLOWED_HOSTS [*]但注意这只是开发用后面部署时一定要收紧。2.3 用虚拟环境把Python和Django隔离刚才提到虚拟环境这里多说一句。新手最容易犯的错是在系统Python里装了一堆包导致版本冲突。不同项目需要不同Django版本比如你另一个项目用Django 5.0而这个源码包要Django 3.2混在一起必炸。虚拟环境就是干这个的。创建和激活的完整流程python -m venv venv source venv/bin/activate python -m pip install --upgrade pip pip install -r requirements.txt python manage.py checkpython manage.py check是Django自带的环境检查命令它不启动服务只检查配置有没有错误。能顺利跑完这步说明依赖和配置基本没问题。如果报错大多是ModuleNotFoundError去requirements里看对应包是否有装。这个命令比直接runserver更早暴露问题我每次拿到新项目都会先跑一遍。3. SQL数据库为什么放一个 .sql 文件从导入到迁移这个资源包标题里明确写了“sql数据库”说明作者提供了一个数据库初始文件。但你要明白Django项目里真正的“数据库”其实是models.py定义的表结构和后续的数据迁移。.sql文件通常包含两类东西一是表结构CREATE TABLE二是基础数据比如漏洞指纹字典、管理员账号。拿到它之后不能直接丢给Django说“用吧”得先搞清它到底是怎么被加载的。3.1 SQLite还是MySQL先分清数据库配置先看settings.py里的ENGINE同时看.sql文件开头有没有CREATE DATABASE或者USE语句。如果文件开头是INSERT INTO说明它只是数据内容如果开头是-- MySQL dump之类说明是为MySQL准备的。常见做法是作者开发时用了MySQL导出成.sql分享但你的复现环境不一定有MySQL。我的处理顺序是先把settings.py的数据库配置改成SQLite然后用Django的迁移生成空表再想办法把.sql里的数据灌进去。但这里有个边界问题如果.sql里的表结构和models.py不一致直接灌会报错。所以更稳妥的做法是只用.sql里的“数据”部分不碰“表结构”部分。例如假设.sql里有一张vul_rule表用来存储漏洞指纹你可以先建一个SQLite数据库然后手动执行其中的部分语句sqlite3 db.sqlite3 data.sql如果data.sql里有MySQL特有语法比如ENGINEInnoDBSQLite会解析失败。这时你需要先把这些行删掉只保留INSERT INTO语句。我一般会用sed或文本编辑器处理一下# 删除MySQL特有行保留INSERT语句 sed -i /ENGINEInnoDB/d data.sql注意这样做的前提是你已确认表名和字段与Django模型一致。不一致的话后面runserver查询时会报“no such table”或“no such column”。3.2 导入.sql数据库文件的两种姿势姿势一如果你决定用MySQL先把服务启动起来然后执行mysql -u root -p db_dump.sql这个命令会把整个备份灌进MySQL。执行前确认db_dump.sql里有CREATE DATABASE或USE scan_db否则数据会进到默认库。灌完后修改settings.pyDATABASES { default: { ENGINE: django.db.backends.mysql, NAME: scan_db, USER: root, PASSWORD: yourpass, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }然后跑python manage.py makemigrations scanner和python manage.py migrate。这里有个关键点如果.sql里已有表结构Django迁移时会发现表存在但迁移记录不存在从而报“Table already exists”。解决方法是假迁移python manage.py migrate --fake-initial这个命令会跳过建表只记录迁移状态。但前提是表结构要和models.py一致否则后面操作会踩坑。姿势二用SQLite。我更喜欢这种省心。先migrate建表然后用Django的loaddata加载JSON格式数据。如果只有.sql没有JSON就写个临时脚本读取.sql中的INSERT语句手动填充。但这样做太费劲不如直接看项目说明里有没有提供initial_data.json。很多作者会同时附一份JSON是给Django的fixtures用的。3.3 Django迁移与数据初始化的顺序一个常见的错误是先导入.sql再migrate结果被覆盖或冲突。正确顺序应该是确保settings.py使用的数据库是目标库SQLite或MySQL。先跑python manage.py makemigrations生成迁移文件如果应用里尚未有。跑python manage.py migrate建表。如果有初始数据再用loaddata或脚本导入。为什么因为Django的迁移系统会记录每个应用的表创建状态。如果你先手工导入.sql建了表Django迁移时不知道这些表是它建的就会尝试再建一次报“Table vul_rule already exists”。这时用--fake-initial可以规避但如果你后续又改了models.py迁移就会乱。所以让Django自己建表再用数据填充是条干净路径。导入后验证一下python manage.py shell from scanner.models import VulRule print(VulRule.objects.count())如果输出数量不对或报错说明数据没导全或字段映射有问题。这时去查项目说明文件看它是否要求你手动执行某个init_data.py脚本。4. 漏洞扫描引擎的核心逻辑任务调度、指纹识别与结果入库源码包的关键价值就在scanner这个应用里。它不像Nmap那样直接命令行扫描而是把扫描任务拆成“目标管理-扫描执行-结果分析-入库展示”的闭环。你拿到源码后先别急着runserver把扫描逻辑读一遍这样才能知道改哪里、调哪些参数。4.1 用Celery还是用Django自带的定时任务很多这类项目的扫描是同步执行的你点一下“开始扫描”请求发起后一直等到扫描完才返回。这在目标少时没问题但如果目标是一段IP段或几百个URL同步执行会让页面卡死。所以源码里往往会看到Celery或者django-crontab。如果源码用了Celery说明扫描任务被放到了异步队列。你会看到类似tasks.pyfrom celery import shared_task from scanner.utils import run_scan shared_task def start_scan_task(scan_id): run_scan(scan_id)调用方式变成start_scan_task.delay(scan_id)。这意味着你需要一个Celery worker在后台跑celery -A scan_project worker -l info如果项目里没有Celery作者可能用ThreadPoolExecutor或者简单的threading.Thread。常见写法是import threading def start_scan(request): scan Scan.objects.create(...) t threading.Thread(targetrun_scan, args(scan.id,)) t.start() return redirect(/scan/detail/{}.format(scan.id))这种做法的优点是轻量缺点是进程重启时任务会丢失且线程数不好控制。如果你要正式用建议改成Celery。注意改Celery不只是加个文件还要在settings.py里配置队列后端比如CELERY_BROKER_URL redis://127.0.0.1:6379/0 CELERY_RESULT_BACKEND redis://127.0.0.1:6379/0没有Redis就起不来。这也是新手最容易翻车的地方装了requirements但没装Redis启动worker直接报连接失败。4.2 端口扫描与HTTP探测的并发参数扫描系统通常分两层先做端口扫描发现开放服务再做HTTP请求识别应用类型。如果你是拿这个源码做Web漏洞扫描重点看它调Nmap或 socket 的代码。以常见的python-nmap为例import nmap def scan_ports(host, ports1-1000): nm nmap.PortScanner() nm.scan(host, ports, arguments-sS -T4 --host-timeout 10) return nm[host][host][tcp]这里的参数-sS是SYN半开扫描需要root权限-T4是时间模板数字越大越快但越容易被发现--host-timeout 10是单个主机超时10秒。新手在没有root时改用-sT或去掉-sS。另外并发控制很重要如果直接对几百个IP调用nm.scanNmap本身是多线程的但Python侧循环串行会慢如果自己用socket.connect_ex做扫描必须用ThreadPoolExecutor限并发比如from concurrent.futures import ThreadPoolExecutor def check_port(host, port): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(0.5) return s.connect_ex((host, port)) 0 with ThreadPoolExecutor(max_workers100) as executor: futures [executor.submit(check_port, host, p) for p in ports]参数说明max_workers100表示最多100个并发线程。设太大会导致本机socket资源耗尽太小则扫描慢。0.5秒的超时对公网主机够用对局域网可以降到0.2。这里必须给读者讲清并发数这个参数是扫描性能的关键我一般根据本机CPU和网络带宽调整不能盲目照抄。4.3 已知漏洞指纹库怎么组织为什么用JSON/数据库表漏洞扫描系统最核心的是“指纹库”——也就是怎么判断目标存在某个漏洞。常见两种实现一种是基于响应内容匹配关键词比如访问/phpmyadmin/返回特定标题就算发现另一种是基于版本号对比比如从HTTP返回头读出X-Powered-By: PHP/5.3.0然后查库看这个版本是否在漏洞列表里。在Django项目里指纹库往往放在一个model里结构类似class VulRule(models.Model): name models.CharField(max_length255) path models.CharField(max_length255) # 要探测的路径 keyword models.TextField() # 响应内容中的关键词 severity models.CharField(max_length10) # 高危/中危/低危 description models.TextField()扫描时遍历所有规则的path发起请求然后用keyword匹配for rule in VulRule.objects.filter(activeTrue): try: resp requests.get(f{target}{rule.path}, timeout5) if rule.keyword in resp.text: VulResult.objects.create(targettarget, rulerule, ...) except requests.RequestException: continue这里有一个效率问题如果指纹库有几百条规则每个目标都要请求几百次很慢。常见优化是用requests.Session()复用连接或者先根据目标应用如识别到Nginx再只跑Nginx相关的规则。另外keyword匹配要小心误报比如首页都可能出现“php”字样所以指纹规则要尽量精确到响应头或特定标签。我在那个踩坑经历里就遇到过一次规则写得太宽把Django后台默认页面扫成了信息泄露。5. 部署运行的避坑清单从数据库连接失败到扫描结果为空这部分是我每次带新人跑这种源码包时都会讲的一组真实教训。你照着前面两步做大概率还会遇到下面几个问题。每条我都写成“现象-原因-解决”方便你对照排查。5.1 数据库表缺失或者字段对不上的坑现象runserver成功但打开扫描列表页时提示OperationalError: no such table: scanner_scantask或者FieldError。原因你在没跑migrate的情况下就直接导入.sql导致Django的迁移记录和实际表结构不一致。更常见的是.sql里的字段和models.py不对应比如作者用的MySQL表字段叫vul_nameDjango模型里叫name。解决如果表完全缺先python manage.py migrate。如果字段对不上需要统一成models.py的字段不要试图去改模型迁就旧.sql。具体操作用Django Admin或者shell里直接查字段名python manage.py shell from scanner.models import VulRule print([f.name for f in VulRule._meta.fields])然后修改models.py或者改数据导入脚本把.sql的列名映射到模型字段。5.2 扫描任务没有写入结果查一下异步任务队列现象创建扫描任务成功页面显示“正在扫描”但过了半天还是“进行中”数据库里也没有结果记录。原因如果项目用了Celery而worker没有启动任务会一直积压在Redis里。如果用的线程方案可能是线程里出现了异常但没捕获导致run_scan中途退出。解决先看项目说明确认它用哪种任务方式。如果是Celery启动worker再试celery -A scan_project worker -l info --concurrency4加--concurrency4是并发worker数量。如果是线程方案在run_scan函数入口加打印def run_scan(scan_id): print(start scan, scan_id) try: ... except Exception as e: print(scan error, e)然后在终端看到输出定位崩溃点。另外检查扫描里是否有sys.exit()或未捕获的requests.exceptions这会导致线程安静退出。5.3 权限与安全别把扫描器暴露在公网现象你把runserver绑定到0.0.0.0:8000想从另一台机器访问结果发现会被各种扫描器盯上。原因Django自带的开发服务器不是给生产用的它不支持HTTPS也没有访问控制。更严重的是你这个系统本身是漏洞扫描器如果被人发现攻击者可以直接用它扫描你的内网资产甚至通过任务注入执行命令。解决本地调试用python manage.py runserver 127.0.0.1:8000就行。如果要内网使用至少加一层验证码或Token。有些源码自带登录功能但默认的SECRET_KEY是公开的攻击者可以伪造会话。拿到源码后第一件事就是改掉settings.py里的SECRET_KEY并设置SECRET_KEY 你的随机字符串 DEBUG FalseDEBUGFalse后如果代码有异常不会把堆栈信息返回给请求者避免泄露路径和数据库结构。5.4 常见报错No module named xxx、Migration 冲突现象pip install -r requirements.txt后仍然报错ModuleNotFoundError: No module named scanner或者django.core.exceptions.ImproperlyConfigured。原因没在项目根目录下运行命令PyCharm终端默认位置可能不对或者requirements.txt不完整有些包是通过代码里动态导入的比如scanner.utils.fingerprint依赖bs4但没写进去。解决先确保当前目录包含manage.py用pwd确认。再装常见缺失包pip install beautifulsoup4 lxml sqlalchemy对于Migration冲突比如你改动过models.py但数据库里已经有迁移记录会出现“Migration scanner.0002 is applied; its parent is missing”之类。解决办法是删掉scanner/migrations/下的冲突文件只保留最新一个然后python manage.py makemigrations scanner python manage.py migrate --run-syncdb注意这个操作会忽略已有的迁移历史如果数据库里已有表--run-syncdb会尝试创建缺失的表而不是更新。所以最好在空库上操作。6. 把系统改造成能用的工具主动扫描、报告导出与定时巡检到这里项目已经能跑扫描也能出结果。但离“好用”还差一步。这个源码包如果只是默认状态功能往往很简陋——没有报告导出没有定时任务结果页就是个表格。下面三个改动是把它变成真正工具的常见方向。6.1 增加一个报告导出接口扫描结果积累后领导或同事要的是PDF或Excel不是让你登录后台截屏。你可以在scanner/views.py里加个导出视图用Django的HttpResponse导出CSVimport csv from django.http import HttpResponse from scanner.models import VulResult def export_csv(request, scan_id): response HttpResponse(content_typetext/csv) response[Content-Disposition] fattachment; filenamescan_{scan_id}.csv writer csv.writer(response) writer.writerow([目标, 漏洞名称, 风险等级, URL, 时间]) for r in VulResult.objects.filter(scan_idscan_id): writer.writerow([r.target, r.rule.name, r.rule.severity, r.url, r.created_at]) return response然后在urls.py里加路由from django.urls import path from scanner import views urlpatterns [ path(scan/int:scan_id/export/, views.export_csv, nameexport_csv), ]参数说明Content-Disposition里的filename如果包含中文最好做一下转码否则可能乱码。CSV格式在Excel里打开中文会乱码可以先写utf-8-sigbin文件。这个方法适合快速交付如果要PDF可以用weasyprint但那个库依赖系统库安装较麻烦。6.2 用Django Admin管理扫描任务和结果Django自带的Admin后台是白送的福利但很多扫描类项目没有好好利用。在admin.py里把模型注册进去就能直接管理from django.contrib import admin from scanner.models import ScanTask, VulResult admin.register(ScanTask) class ScanTaskAdmin(admin.ModelAdmin): list_display (id, target, status, created_at) list_filter (status,) admin.register(VulResult) class VulResultAdmin(admin.ModelAdmin): list_display (target, rule, severity, created_at) search_fields (target,)list_display控制在后台列表页显示哪些列list_filter是侧边栏筛选search_fields是搜索框字段。这几个参数是后台好不好用的关键。我把它们调好后日常给同事开个只读权限他们直接进Admin看结果不用再改代码。6.3 验证扫描结果跑一个本地靶场你改完系统怎么知道扫描器真能发现漏洞不能随便对公网目标扫那可能违法。常见做法是在本地搭一个靶场比如DVWADamn Vulnerable Web Application。你不需要全搭只要能模拟一个漏洞即可。比如用Django写个最简单的测试接口from django.http import JsonResponse def test_xss(request): msg request.GET.get(msg, ) return JsonResponse({msg: msg})这个接口把参数原样返回扫描器的XSS规则里如果有“参数值出现在响应中”的逻辑就能触发。但这只是粗验证。更标准的是用sqlite3建一个测试任务目标指向http://127.0.0.1:8000/test_xss?msgscript看扫描结果里能不能记录到。如果没有记录说明规则匹配逻辑有问题或者任务参数里没启用该规则。验证完成后你还可以给扫描加一个“定时巡检”的功能用Django的management command配合系统cron或者用django-crontab。比如创建一个命令python manage.py daily_scan把它加进crontab0 2 * * * cd /opt/scan /opt/scan/venv/bin/python manage.py daily_scan这里我用绝对路径的venv python避免cron环境里找不到虚拟环境。定时巡检的意义在于漏洞不是一天出现的新部署的服务、新上线的页面都可能是隐患。我自己的习惯是每周对核心资产扫一次并把结果导出到内部Wiki。这个习惯让我在两次被通报“存在漏洞”之前就修掉了问题算是血泪经验换来的。最后多说一句这套Django漏洞扫描系统源码不是拿来就完事的它更像是给你搭了一个台子。真正决定它好不好用的是你往里填多少指纹规则、调多合理的并发参数、搭多顺畅的定时任务。我踩过的坑就是一开始照抄默认并发结果扫描某个内网段时把办公网的网段扫挂了后来加了超时和限速才老实。希望帮到你少走点弯路。本文还有配套的精品资源点击获取
返回列表