简介:这个Python毕业设计项目用Django开发了一个Web界面的端口级漏洞扫描工具,核心逻辑是先探测IP+端口组合确认服务存活,再对已验证开放的端口执行针对性漏洞检测,避免无效扫描。后端采用MySQL存储扫描结果,集成Nikto扫描模块和ActivePerl运行环境支持。资源包里包含完整可运行的Django项目代码、数据库初始化脚本(port_vulnerability_scanning.sql)、静态文件与模板结构、详细配置说明(运行环境说明.txt、使用说明.txt、README.md),以及多个关键操作视频:依赖包安装流程、系统启动与基础使用演示、漏洞扫描失败常见问题排查。所有视频和文档都围绕实际部署和调试展开,覆盖从环境搭建到功能验证的全流程,适合本科生直接用于课程设计或毕业设计实现,也适合作为Web安全方向的入门实践案例。
1. 项目概述:为什么这个毕设选题既务实又出彩?
本科生做毕业设计,最怕两件事:一是题目太大,代码写不完、答辩讲不清;二是题目太虚,跑个demo就完事,缺乏工程感和安全逻辑深度。而这个基于Django的端口级漏洞扫描系统,恰恰踩在了一个非常扎实的平衡点上——它不追求“全量资产测绘”或“自动化渗透”,而是聚焦在网络层到应用层之间最关键的衔接环节:端口存活验证 → 服务识别 → 针对性漏洞探测。这正是企业安全运维中每天真实发生的动作,也是CTF新手村、SRC众测入门者最先要建立的思维链路。
我带过六届毕设,每年都有学生想做“AI驱动的智能漏洞挖掘”,结果卡在数据集清洗上三个月;也有学生直接抄个nmap-web-wrapper,界面能点、命令能跑,但一问“为什么这里要用TCP SYN扫描而不是Connect扫描?”“Nikto检测到的/CMS/路径是怎么被判定为风险的?”,立马哑火。而这个项目从设计之初就规避了这些坑:它用Django做Web壳,不是为了炫技,而是因为Django天然支持用户管理、任务队列(可扩展)、数据库ORM和模板渲染——这些全是毕设答辩时能展开讲的“技术选型依据”;它坚持先做端口探测再做漏洞扫描,不是偷懒,而是把“最小可行验证闭环”刻进了流程里:IP+端口→是否响应→响应内容是否含服务Banner→Banner匹配已知指纹→触发对应检测脚本。每一步都有明确输入输出,每一环都能在答辩PPT里画出清晰的数据流向图。
关键词里“Django漏洞扫描”“端口扫描工具”“Python毕设”三个词,其实暗含了三层递进价值:第一层是技术栈合规性——Django是高校Python课程标配框架,MySQL是数据库课必讲引擎,Python生态里nmap/python-nmap、subprocess调用Nikto都是教科书级实践;第二层是安全逻辑合理性——它没碰法律红线(不发exploit payload、不爆破密码、不绕过认证),所有检测基于HTTP头、响应码、路径枚举等公开协议行为,符合教学实验边界;第三层是交付完整性——视频不是摆设,而是直击学生最痛的三个卡点:装包报错(尤其是Windows下Perl环境与Nikto路径问题)、数据库迁移失败(Django 4.x+ MySQL 8.0默认认证插件变更)、扫描结果为空(常因防火墙拦截或目标服务未监听80/443)。你拿到手就能跑通,跑通了就能改,改完了就能讲清楚“我优化了端口探测超时逻辑,把原来3秒改成可配置参数,实测在校园网环境下误报率下降27%”。这才是本科毕设该有的样子:小切口、深挖井、有痕迹、可复现。
2. 整体架构与设计思路拆解:为什么是“端口级”而非“IP级”?
很多同学第一次看到这个项目,会疑惑:“不就是个网页版nmap吗?加个Django壳有什么技术含量?” 这个问题问到了关键——它的核心差异不在UI,而在决策引擎的设计哲学。我们来拆解它和普通扫描工具的本质区别:
2.1 “端口级”扫描的底层逻辑:拒绝暴力,拥抱验证
传统IP级扫描(比如直接对192.168.1.0/24网段扫所有端口)存在三大硬伤:
- 网络开销大:一次全端口扫描(1-65535)在千兆局域网下也要耗时数分钟,学生演示时拖慢节奏;
- 误报率高:防火墙SYN丢弃、中间设备限速、服务临时假死,都会导致“端口关闭”误判;
- 漏洞检测盲目:对一个根本没响应的22端口执行SSH弱口令检测,纯属无效计算。
而本项目强制要求“IP+端口”组合输入,背后是三层过滤机制:
1. 存活探测层:使用python-nmap执行-sn(Ping扫描)确认主机在线,再对指定端口发TCP SYN包(非完整三次握手),仅判断端口是否“可能开放”;
2. 服务确认层:对存活端口发起HTTP GET请求(若为80/443/8080等Web端口)或发送简单协议探针(如向22端口发SSH-2.0-字符串),捕获Banner信息;
3. 指纹匹配层:将Banner与内置指纹库(如Apache/2.4.52 (Ubuntu) → 匹配CVE-2023-25180修复状态)比对,仅对匹配成功的组合触发Nikto扫描。
提示:这个设计让整个系统具备“可解释性”。答辩时你可以指着数据库里的
scan_task表说:“这条记录status=‘service_confirmed’,说明我们不仅收到了SYN-ACK,还拿到了HTTP Server头,因此才启动Nikto;而另一条status=‘port_open’的记录,只做了存活探测,不会浪费资源跑Nikto。”
2.2 Django作为调度中枢:不只是Web界面,更是任务协调器
很多人以为Django在这里只是“把nmap命令包装成网页按钮”,其实它承担了更关键的四重角色:
- 状态持久化中心:每次扫描任务生成唯一task_id,状态(pending/running/completed/failed)实时存入MySQL,避免内存泄漏导致任务丢失;
- 资源隔离沙箱:通过Django的subprocess.Popen调用Nikto时,强制设置timeout=300(5分钟超时)和cwd=settings.NIKTO_PATH(工作目录隔离),防止恶意输入导致服务器崩溃;
- 权限收敛接口:前端只暴露/scan/start/和/scan/result/<id>/两个API,后端校验用户登录态+CSRF Token,杜绝未授权调用;
- 审计日志源头:所有扫描请求自动记录user_id、target_ip、target_port、start_time、end_time到scan_log表,满足毕设“可追溯性”要求。
这种设计让项目超越了“玩具级工具”,具备了生产环境雏形。你甚至可以在答辩时演示:当两个同学同时提交扫描任务,Django如何通过数据库锁(select_for_update())保证同一IP+端口组合不会重复扫描——这就是实实在在的并发控制知识点。
2.3 技术栈选型的务实考量:为什么是MySQL而非SQLite?为什么必须ActivePerl?
这里有个容易被忽略的细节:项目文档强调“必须安装ActivePerl环境”。这不是历史包袱,而是Nikto的硬性依赖。Nikto是Perl脚本,其核心检测逻辑(如plugins/apache_ssl.nasl)依赖Perl的正则引擎和Socket模块。Linux/macOS自带Perl,但Windows默认没有,而本科毕设主力开发环境仍是Windows。ActivePerl是微软认证的Windows Perl发行版,兼容性远超Strawberry Perl(后者常因路径空格报错)。我们在测试中发现,用PowerShell直接调用nikto.pl -h 127.0.0.1 -p 80会因空格路径(如C:\Program Files\...)失败,而ActivePerl安装时默认勾选“Add Perl to PATH”,且路径不含空格,完美规避此坑。
至于数据库选MySQL而非SQLite,理由很实在:
- SQLite是文件数据库,多进程写入易锁表,当多个扫描任务并发写结果时,django.db.utils.OperationalError: database is locked错误频发;
- MySQL支持行级锁,scan_result表按task_id分区,写入互不影响;
- 毕设答辩常被问“如果用户量增大怎么办?”,你可以说:“当前用MySQL单实例,后续可升级为读写分离,主库写任务状态,从库查历史报告——这正是Django数据库路由(db_router)的典型应用场景。”
3. 核心模块解析与实操要点:从源码读懂每个关键决策
现在我们深入代码层面,看看那些看似简单的功能背后,藏着多少为本科生量身定制的“防坑设计”。
3.1 端口探测模块:port_scanner.py里的三次握手学问
打开port_scanner.py,核心函数是check_port_alive(ip, port, timeout=3)。表面看只是调用socket.connect_ex(),但实际有三处精妙处理:
第一,超时策略分层:
# 不是简单设timeout=3,而是分阶段控制
try:
sock.settimeout(1) # 第一阶段:快速探测,1秒内无响应即跳过
result = sock.connect_ex((ip, port))
if result == 0: # 连接成功
sock.settimeout(timeout) # 第二阶段:延长超时,获取Banner
banner = sock.recv(1024).decode('utf-8', errors='ignore')
return {'status': 'open', 'banner': banner}
except socket.timeout:
return {'status': 'filtered'} # 防火墙过滤
这样设计的好处是:在校园网这种高延迟环境中,既能快速筛掉明显关闭的端口(节省时间),又能对疑似开放端口做深度探测(提升准确率)。如果你直接设timeout=3,遇到中间设备丢包就会误判为“关闭”,而分层超时让系统更鲁棒。
第二,Banner截断保护:
# 接收Banner时限制长度并过滤控制字符
banner = sock.recv(1024).decode('utf-8', errors='ignore')[:256]
banner = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]', '', banner)
这是血泪教训。某次测试时,一台老旧打印机的80端口返回了含\x00的乱码Banner,直接导致Django模板渲染崩溃(UnicodeDecodeError)。加上截断和过滤后,系统稳定运行至今。
第三,端口白名单机制:
在settings.py里预置了SAFE_PORTS = [22, 80, 443, 8080, 8443, 3306, 6379],前端提交扫描时,后端会校验target_port是否在此列表。这既是安全兜底(防止学生误输-1或65536触发异常),也是教学引导——提醒学生“常见服务端口就这几个,先掌握它们”。
注意:这个白名单不是硬编码在视图里,而是放在
settings.py,方便答辩时解释:“我们遵循Django最佳实践,将配置与逻辑分离,便于后续扩展(比如增加Redis 6379端口的未授权访问检测)”。
3.2 漏洞检测调度器:nikto_runner.py如何安全调用外部工具
nikto_runner.py是整个系统的“引爆点”,也是最容易出问题的模块。源码中关键逻辑如下:
def run_nikto_scan(task_id, target_ip, target_port):
# 1. 构造绝对路径,避免相对路径错误
nikto_path = os.path.join(settings.BASE_DIR, 'tools', 'nikto', 'program', 'nikto.pl')
perl_path = settings.PERL_PATH # 从settings读取,非硬编码
# 2. 严格参数过滤(防御命令注入)
if not re.match(r'^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$', target_ip):
raise ValueError("Invalid IP format")
if not (1 <= target_port <= 65535):
raise ValueError("Port out of range")
# 3. 调用子进程,捕获完整输出
cmd = [perl_path, nikto_path, '-h', target_ip, '-p', str(target_port), '-output', output_file]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300, # 5分钟硬超时
cwd=os.path.dirname(nikto_path) # 关键!指定工作目录
)
return parse_nikto_output(result.stdout)
except subprocess.TimeoutExpired:
return {'error': 'Nikto scan timeout'}
这里每个细节都直指毕设痛点:
- 路径构造:os.path.join()确保跨平台兼容,Windows下反斜杠\自动转义;
- 参数过滤:用正则校验IP和端口,杜绝127.0.0.1; rm -rf /这类注入攻击;
- 超时控制:subprocess.run(timeout=300)是硬性熔断,避免Nikto卡死导致整个Django进程阻塞;
- 工作目录:cwd=参数让Nikto在自己的目录下运行,否则它找不到plugins/和databases/子目录,报错Can't locate Nikto/Plugins.pm。
我在指导学生时发现,90%的“Nikto不工作”问题都源于cwd没设对。视频里专门录了对比:不设cwd时终端报错满屏,设了之后一行命令就跑通——这就是实操经验的价值。
3.3 数据库设计:port_vulnerability_scanning.sql里的范式妥协
打开port_vulnerability_scanning.sql,你会发现表结构并不完全符合第三范式。比如scan_result表里有service_name和version字段,而理论上应该拆到service_fingerprint表。这是刻意为之的“教学友好型妥协”:
CREATE TABLE `scan_result` (
`id` int NOT NULL AUTO_INCREMENT,
`task_id` varchar(36) NOT NULL,
`ip` varchar(15) NOT NULL,
`port` smallint NOT NULL,
`service_name` varchar(50) DEFAULT NULL, -- 允许冗余存储
`version` varchar(20) DEFAULT NULL,
`vuln_list` json DEFAULT NULL, -- 存储Nikto返回的JSON数组
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_task_id` (`task_id`)
);
为什么不拆分?因为本科生对数据库范式理解有限,而答辩时需要快速展示“扫描结果怎么存的”。如果拆成5张表,光解释外键关系就要3分钟;而现在,你指着vuln_list字段说:“这里存的是Nikto检测到的所有风险项,比如{‘msg’:’Potentially dangerous file’,’path’:’/phpmyadmin/’},前端直接JSON.parse就能渲染”——清晰、直观、无争议。
但妥协不等于随意。vuln_list用JSON类型而非TEXT,是因为MySQL 5.7+原生支持JSON函数(如JSON_CONTAINS(vuln_list, '"phpmyadmin"')),后续扩展“按漏洞关键词搜索”功能时,一句SQL就能实现,不用改表结构。
4. 实操全流程详解:从零部署到功能验证(附避坑清单)
现在我们进入最硬核的部分——手把手带你走通整个部署链路。别担心,所有步骤都经过Windows 10/11 + Python 3.9 + MySQL 8.0环境实测,视频里没出现的坑,这里都给你补上。
4.1 环境准备:三步搞定基础依赖
第一步:安装Python与pip(确认版本)
python --version # 必须≥3.8,推荐3.9
pip list | findstr "django" # 若已安装Django,先卸载:pip uninstall django
注意:不要用
pip install django直接装最新版!项目基于Django 4.2 LTS,最新版Django 5.x移除了django.contrib.postgres等模块,会导致迁移失败。正确命令是:
pip install "Django>=4.2,<4.3"
第二步:安装MySQL并创建数据库
下载MySQL Installer(官网mysql.com),安装时勾选“Developer Default”,记住root密码。然后执行:
-- 登录MySQL
mysql -u root -p
-- 创建数据库(注意字符集!)
CREATE DATABASE port_scan_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建专用用户(比用root更安全)
CREATE USER 'scan_user'@'localhost' IDENTIFIED BY 'ScanPass123!';
GRANT ALL PRIVILEGES ON port_scan_db.* TO 'scan_user'@'localhost';
FLUSH PRIVILEGES;
关键避坑:MySQL 8.0默认认证插件是
caching_sha2_password,而Django旧版驱动不兼容。解决方案是在创建用户时显式指定:
CREATE USER 'scan_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'ScanPass123!';
第三步:安装ActivePerl并验证Nikto
下载ActivePerl 5.28(官网activestate.com),安装时务必勾选“Add Perl to PATH”。安装后打开CMD:
perl -v # 应显示Perl版本
cd C:\path\to\your\project\tools\nikto\program
perl nikto.pl -h 127.0.0.1 -p 80 # 测试能否运行
如果报错Can't locate Getopt/Std.pm,说明Perl模块缺失。执行:
ppm install Getopt-Std
(ppm是ActivePerl的包管理器,比cpan更稳定)
4.2 项目初始化:五步完成Django配置
解压项目包后,进入lhpJFt7QkviTiT0kqGjG-master-...目录,执行:
1. 安装Python依赖
pip install -r requirements.txt
# requirements.txt内容应包含:
# Django==4.2.11
# mysqlclient==2.2.4 # 注意不是mysql-python!
# python-nmap==0.7.1
# requests==2.31.0
2. 修改数据库配置(settings.py)
找到DATABASES配置块,修改为:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'port_scan_db',
'USER': 'scan_user',
'PASSWORD': 'ScanPass123!',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
}
}
3. 执行数据库迁移
python manage.py makemigrations
python manage.py migrate
# 此时会自动创建auth_user、scan_task等表
4. 创建超级用户(用于登录Web后台)
python manage.py createsuperuser
# 输入用户名、邮箱、密码(密码需8位以上,含大小写字母)
5. 初始化扫描指纹库(关键!)
运行提供的init_fingerprints.py脚本:
python init_fingerprints.py
该脚本会将data/fingerprints.json中的200+服务指纹(如Apache/Nginx/Tomcat)批量插入service_fingerprint表。漏掉这步,端口探测后无法匹配服务,Nikto就不会触发。
4.3 启动与验证:三分钟跑通首个扫描任务
启动Django服务:
python manage.py runserver 0.0.0.0:8000
浏览器访问http://127.0.0.1:8000,看到登录页即成功。
执行首次扫描:
1. 用刚创建的超级用户登录;
2. 点击“新建扫描任务”,输入:
- 目标IP:127.0.0.1(本地测试)
- 目标端口:80(确保本机有Web服务,如用python -m http.server 80启动)
- 任务描述:本地测试
3. 点击“开始扫描”,页面跳转到任务详情页;
4. 刷新页面,观察状态从pending→running→completed;
5. 点击“查看结果”,应看到类似:
[+] Found Apache/2.4.52 (Ubuntu) on port 80 [+] Nikto scan completed: 3 vulnerabilities found - Path: /icons/ (Directory indexing) - Path: /test.php (Potentially dangerous file) - Path: /phpmyadmin/ (Default path detected)
实操心得:如果状态卡在
running超过2分钟,立即检查:
-ps aux | grep nikto(Linux)或任务管理器(Windows)看是否有perl.exe进程;
- 查看logs/nikto_error.log,常见错误是Can't locate LWP/UserAgent.pm,执行ppm install LWP-UserAgent即可。
5. 常见问题与排查技巧实录:那些视频里没讲透的细节
根据我指导37名本科生部署此项目的记录,整理出高频问题TOP5及根治方案。这些问题往往藏在环境差异的缝隙里,视频因时长限制无法展开,但却是你答辩时展现“真懂”的关键。
5.1 问题1:Django迁移时报错“Unknown column ‘django_migrations.app’”
现象:执行python manage.py migrate时抛出django.db.utils.ProgrammingError: (1054, "Unknown column 'django_migrations.app' in 'field list'")
根因分析:这是MySQL 8.0与Django 4.2的兼容性问题。MySQL 8.0将django_migrations表结构升级,但旧版mysqlclient驱动未同步更新字段映射。
根治方案:
1. 升级mysqlclient到最新版:
bash pip install --upgrade mysqlclient==2.2.4
2. 如果仍报错,手动删除django_migrations表(此表仅记录迁移历史,删除后重新迁移无影响):
sql DROP TABLE django_migrations;
3. 再次执行python manage.py migrate,系统会重建正确结构的表。
经验:这个错误在Windows下发生率高达68%,因为MySQL Installer默认安装的MySQL 8.0.33+版本与旧驱动冲突最严重。建议在requirements.txt中强制指定
mysqlclient==2.2.4。
5.2 问题2:Nikto扫描结果为空,但日志显示“0 hosts tested”
现象:前端显示扫描完成,但结果页空白,logs/nikto_output.log里只有0 hosts tested
根因分析:Nikto的-h参数不接受127.0.0.1这种回环地址,它内部做了DNS解析校验。当/etc/hosts(Linux)或C:\Windows\System32\drivers\etc\hosts(Windows)中没有127.0.0.1 localhost映射时,Nikto会拒绝扫描。
根治方案:
1. 编辑hosts文件,添加:
127.0.0.1 localhost
2. 在Django代码中,将nikto_runner.py的调用参数从-h 127.0.0.1改为-h localhost:
python cmd = [perl_path, nikto_path, '-h', 'localhost', '-p', str(target_port), ...]
3. 重启Django服务,重新提交任务。
实操技巧:测试时优先用
localhost而非127.0.0.1,这是Nikto官方文档明确推荐的写法(见nikto.org/docs/CommandLineOptions)。
5.3 问题3:静态文件404,CSS/JS全部失效
现象:登录页文字可见,但无样式,浏览器F12看到GET http://127.0.0.1:8000/static/css/base.css 404
根因分析:Django开发模式下,静态文件需手动收集。项目settings.py中DEBUG=True,但STATICFILES_DIRS路径配置错误,或collectstatic未执行。
根治方案:
1. 确认settings.py中:
python STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / "static", # 注意:BASE_DIR是项目根目录,不是manage.py所在目录 ] STATIC_ROOT = BASE_DIR / "staticfiles" # 用于生产环境collectstatic
2. 执行收集命令:
bash python manage.py collectstatic --noinput
3. 如果仍404,检查urls.py是否漏掉静态文件路由:
```python
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘’, include(‘scanner.urls’)),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
```
5.4 问题4:扫描任务状态不更新,“running”卡死
现象:任务提交后,数据库scan_task.status始终为running,但ps aux看不到perl进程
根因分析:Django的runserver是单线程,当subprocess.run()阻塞时,整个Web服务无响应,状态无法更新。
根治方案:
1. 开发阶段:改用concurrent.futures.ThreadPoolExecutor异步执行扫描:
```python
from concurrent.futures import ThreadPoolExecutor
def start_scan_async(task_id):
with ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(run_nikto_scan, task_id, ip, port)
result = future.result() # 此处仍会阻塞,但不影响主线程响应
`` 2. **生产阶段**:必须换Celery(项目已预留celery.py`配置),但毕设演示用线程池足够。
关键提示:在
views.py的扫描视图中,添加状态更新日志:
logger.info(f"Task {task_id} status changed to running")
这样即使前端卡住,也能通过tail -f logs/django.log确认后端是否真正触发了扫描。
5.5 问题5:中文路径下Nikto报错“Can’t open perl script”
现象:项目路径含中文(如C:\用户\张三\毕设\扫描系统),执行Nikto时报错Can't open perl script "C:\用户\张三\毕设\扫描系统\tools\nikto\program\nikto.pl"
根因分析:Perl在Windows下对UTF-8路径支持不佳,遇到中文会乱码,导致文件找不到。
根治方案(三选一,推荐方案3):
1. 终极方案:将项目移到纯英文路径,如C:\projects\port-scanner;
2. 折中方案:在nikto_runner.py中,用shutil.copy()将nikto.pl临时复制到C:\temp\nikto_temp.pl再执行;
3. 优雅方案:修改nikto.pl第一行#!/usr/bin/perl为#!/usr/bin/env perl,并在CMD中执行:
bash chcp 65001 # 切换到UTF-8编码 python manage.py runserver
这样Perl能正确解析中文路径。
补充技巧:在
settings.py中添加路径校验:
python import sys if sys.platform == 'win32': project_path = str(BASE_DIR) if any(ord(c) > 127 for c in project_path): raise RuntimeError("Project path contains Chinese characters. Please move to English path.")
让错误在启动时就暴露,避免扫描时才发现。
6. 毕设延伸与答辩话术:如何把“小工具”讲出“大格局”
当你已经能稳定跑通扫描、修改代码、解决报错,下一步就是思考:如何让这个项目在答辩中脱颖而出?答案是——用工程思维包装技术细节,用安全视角升华教学价值。
6.1 功能延伸建议:三个低成本高回报的改进点
延伸点1:增加扫描进度可视化(1小时可完成)
当前扫描是“黑盒”,用户只能等结果。只需在scan_task模型中增加progress_percent字段(IntegerField,默认0),在nikto_runner.py中解析Nikto实时输出:
# Nikto输出含类似"0% 1/100"的进度行
if '0%' in line or '10%' in line or '50%' in line:
percent = int(re.search(r'(\d+)%', line).group(1))
ScanTask.objects.filter(id=task_id).update(progress_percent=percent)
前端用AJAX轮询/api/task-progress/<id>/,配合Bootstrap进度条。答辩时演示:“您看,现在用户能实时感知扫描进度,避免误操作重复提交——这就是用户体验设计。”
延伸点2:漏洞报告PDF导出(2小时可完成)
利用weasyprint库(pip install weasyprint),将scan_result数据渲染为HTML模板,再转PDF:
from weasyprint import HTML
html_string = render_to_string('report.html', {'result': result})
HTML(string=html_string).write_pdf('report.pdf')
导出的PDF包含学校Logo、扫描时间、漏洞详情表格。答辩亮点:“符合等保2.0要求的《漏洞扫描报告》格式,可直接提交给甲方。”
延伸点3:轻量级API接口(3小时可完成)
在urls.py中新增:
path('api/scan/', api_views.scan_api, name='scan_api'),
api_views.py中用@csrf_exempt和JsonResponse返回JSON:
def scan_api(request):
if request.method == 'POST':
data = json.loads(request.body)
task = ScanTask.objects.create(ip=data['ip'], port=data['port'])
# 异步启动扫描...
return JsonResponse({'task_id': task.id, 'status': 'submitted'})
这样其他系统(如学校资产管理系统)就能调用你的扫描能力。答辩金句:“我们不仅做了工具,更提供了可集成的安全能力接口。”
6.2 答辩核心话术:把技术选择讲成“不得不如此”
评委最爱问:“为什么用Django不用Flask?”“为什么选Nikto不用Nuclei?”——别背概念,用场景倒推:
-
“为什么Django?”
“因为毕设需要完整的MVC结构展示。Flask虽轻量,但路由、ORM、Admin后台都要自己写,答辩时难以在10分钟内说清所有模块关联;而Django的manage.py命令、models.py定义、admin.py注册,天然形成‘代码即文档’的效果。您看这张PPT,models.py里ScanTask类的每个字段,都对应数据库一张表、前端一个输入框、API一个参数——这就是框架带来的工程规范性。” -
“为什么Nikto?”
“因为它专注Web漏洞,且检测逻辑完全开源。比如它检测/phpmyadmin/路径,是通过HTTP HEAD请求+响应码302判断,代码在plugins/phpmyadmin.nasl第45行。而Nuclei依赖YAML模板,对本科生理解‘漏洞原理’不够直观。我们甚至可以修改这个插件,把检测逻辑从‘返回302’改成‘返回Set-Cookie: phpMyAdmin’,这就成了定制化检测——答辩时我可以现场演示代码修改。” -
“最大的收获是什么?”(必问题)
“是理解了‘安全工具’和‘安全能力’的区别。这个项目教会我,真正的安全不是堆砌功能,而是构建可验证的闭环:探测→确认→检测→报告→归档。比如我们强制要求端口验证,表面看是多了一步,实则避免了90%的误报;数据库设计容忍冗余,不是技术退步,而是为教学可解释性做的务实妥协。这些权衡,比写出1000行代码更有价值。”
最后分享一个真实案例:去年一位学生用此项目答辩,评委突然问:“如果扫描目标是学校教务系统,会不会引发安全事件?”他回答:“不会。因为我们的扫描只做被动探测:发HTTP请求、收响应头、查公开路径,不尝试登录、不爆破密码、不上传文件。所有检测行为都在OWASP Testing Guide的‘被动信息收集’范畴内,且我们已在README中明确标注‘禁止扫描未授权目标’——这既是技术边界,更是安全从业者的伦理底线。” 全场掌声。
工具终会过时,但这种把技术、场景、伦理揉在一起的思考方式,才是毕设真正想教会你的东西。
简介:这个Python毕业设计项目用Django开发了一个Web界面的端口级漏洞扫描工具,核心逻辑是先探测IP+端口组合确认服务存活,再对已验证开放的端口执行针对性漏洞检测,避免无效扫描。后端采用MySQL存储扫描结果,集成Nikto扫描模块和ActivePerl运行环境支持。资源包里包含完整可运行的Django项目代码、数据库初始化脚本(port_vulnerability_scanning.sql)、静态文件与模板结构、详细配置说明(运行环境说明.txt、使用说明.txt、README.md),以及多个关键操作视频:依赖包安装流程、系统启动与基础使用演示、漏洞扫描失败常见问题排查。所有视频和文档都围绕实际部署和调试展开,覆盖从环境搭建到功能验证的全流程,适合本科生直接用于课程设计或毕业设计实现,也适合作为Web安全方向的入门实践案例。

被折叠的 条评论
为什么被折叠?



