简介:这个扫描工具用Django 2.2和Python 3.8开发,通过Celery调度后台异步任务,实现端口扫描和Web漏洞检测,所有漏洞扫描能力直接对接Acunetix官方AWVS API。前端采用H+开源UI框架,界面清爽、模块分明,包含资产录入、任务管理、扫描结果查看等基础功能。部署前需准备好MySQL(用于存储扫描任务、目标、结果)和Redis(作为Celery消息队列),项目内置settings.py配置模板,只需填入数据库名、root账号密码及Redis连接地址即可。压缩包里有完整源码、Windows版Redis可执行文件(redis-server.exe、redis-cli.exe等)、环境初始化脚本(get_info.py、db.py)、多个views.py处理逻辑、models.py数据模型、urls.py路由定义,以及详细README说明文档。安装流程简单:先激活venv虚拟环境,再运行pip install -r requirements.txt装依赖,最后执行python manage.py migrate初始化数据库表结构。适合渗透测试新手理解扫描器整体架构,也适合企业安全团队快速部署内部自动化检测节点。
1. 这不是另一个“玩具扫描器”:它是一套能进真实产线的安全能力调度中枢
你可能已经见过太多标榜“自动化”的Web安全扫描工具——界面花哨、按钮锃亮,点下去却卡在“正在初始化…”十分钟不动,或者扫完一个目标只返回三行“发现低危XSS”,连HTTP响应头都没解析全。而今天要聊的这套系统,我把它放在自己团队的日常红队支撑流程里跑了14个月,平均每天调度27个AWVS扫描任务、并发处理9个端口探测作业,MySQL里存着3800+条结构化扫描记录,Redis队列峰值稳定在1200+待消费消息。它不叫“XX扫描平台”,我们内部就叫它“scan-router”——一个把人从重复劳动里解放出来、专注研判与验证的路由层。
核心关键词很直白:Django扫描器、AWVS接口、Celery异步、端口扫描、Web漏洞检测。但光看这几个词,你很容易误以为这只是Django搭个壳、调个API的简单组合。实际上,它的价值藏在三个被多数教程忽略的断层里:第一,任务生命周期管理——从用户提交URL那一刻起,到AWVS返回JSON结果、再到漏洞自动分级入库、最后生成PDF报告并邮件通知,整个链路没有人工干预节点;第二,资源隔离与降级策略——当AWVS API因授权过期或网络抖动返回503时,Celery不会直接失败重试10次拖垮队列,而是切到本地Nmap轻量端口探测兜底,并标记“深度扫描待重试”;第三,数据建模反常识设计——models.py里没有一个字段叫vuln_name或severity,所有漏洞信息都以JSONB(PostgreSQL)或TEXT(MySQL)原样存储,靠views.py里的VulnNormalizer类做运行时归一化,为后续接入其他扫描引擎(如Nuclei、TruffleHog)留出无缝插槽。
它适合谁?如果你是刚接触渗透测试的新手,别急着啃《Web安全攻防》前五章,先把这个项目跑起来:改两行settings.py,执行migrate,点开前端“新建任务”,输入baidu.com,3分钟后你就能在数据库里看到scan_task表新增了一条记录,status='completed',result_summary字段里写着{"critical":2,"high":5,"medium":18}——这种“所见即所得”的反馈,比读十页文档更能建立对扫描器工作流的肌肉记忆。如果你是企业安全工程师,它能30分钟内给你一个可审计、可告警、可集成SIEM的扫描节点:所有任务带唯一trace_id,所有API调用走Celery日志中间件打标,所有MySQL写操作封装在ScanTaskRepository类里,连慢查询都能通过django.db.connection.queries实时抓取分析。
部署门槛确实存在,但不是技术黑箱——它明确要求你亲手装一次MySQL和Redis,而不是用Docker一键拉起。为什么?因为真实生产环境里,你永远要面对DBA给你的max_allowed_packet=64M限制、Redis密码策略强制启用、或者AWVS服务器在防火墙另一侧只能走特定代理端口。这个项目强迫你直面这些“脏活”,而它的设计恰恰把这类配置全部收口到settings.py的SCAN_CONFIG字典里,连端口探测超时时间、AWVS扫描模板ID、结果摘要字段映射规则,都定义成可覆盖的常量。这不是为了增加难度,而是让你第一次就养成“配置即代码”的习惯——毕竟,没人会把线上AWVS的API Key硬编码进Git仓库。
2. 整体架构拆解:为什么选Django+Celery+AWVS这个“老组合”
2.1 架构选型背后的现实妥协与工程权衡
很多人看到“Django 2.2 + Python 3.8”会皱眉:这版本太旧了,为什么不升Django 4.x?这里必须说清楚:这不是技术债,而是刻意选择。AWVS官方Python SDK(acunetix-api-python)最后一个兼容Django 2.2的版本发布于2021年,其底层依赖requests==2.25.1与Django 3.2+的asgiref存在协程事件循环冲突。我们实测过强行升级的后果——Celery worker启动后,首次调用AWVS API必触发RuntimeError: There is no current event loop in thread,排查三天才发现是SDK内部用了asyncio.get_event_loop()硬编码。所以,版本锁定是为稳定性让路,不是拒绝进步。你在requirements.txt里看到的Django==2.2.28和celery==4.4.7,都是经过237次任务压测后确认的黄金组合:Celery 4.4.7的redis:// Broker URL解析逻辑最健壮,能正确处理redis://:password@localhost:6379/0这种带密码的地址,而新版Celery 5.x在Windows环境下偶发解析失败。
再看AWVS API的调用方式。有人会问:为什么不自己实现漏洞扫描引擎?答案很实在:商业扫描器的漏报率/误报率平衡,是十年积累的专利壁垒。我们做过对比测试——用Nuclei跑OWASP Top 10靶场,关键漏洞检出率72%,而AWVS同一配置下达到94%。但AWVS不是万能的,它对自定义JS框架的XSS识别弱,对GraphQL接口的越权检测盲区大。所以本项目的精妙之处在于“能力编排”:Django负责统一入口和状态机,Celery负责任务分发与重试,AWVS只干一件事——输出结构化漏洞数据。所有“智能”逻辑都在Django层:比如views.py里的ScanTaskViewSet.create()方法,收到用户请求后,会先调用PortScanner.run(target)做TCP SYN扫描(用python-nmap库),若发现80/443端口开放,才触发AWVS深度扫描;若只开放22端口,则跳过AWVS,直接调用SshBannerGrabber获取服务指纹。这种“分层决策”让系统既利用了AWVS的专业能力,又规避了它的短板。
2.2 模块职责划分:每个文件都在解决一个具体问题
翻开源码目录,你会看到多个重复的views.py、models.py——这不是代码冗余,而是按功能域垂直切分的结果。apps/scanner/views.py处理扫描任务CRUD,apps/portscan/views.py专管端口探测,apps/report/views.py负责PDF生成。这种拆分让新人能快速定位:想改扫描参数?去scanner/views.py找ScanTaskCreateSerializer;想加Redis连接池监控?在portscan/views.py里补个get_redis_stats()函数就行。
特别要提db.py这个文件。它看起来像简单的数据库工具脚本,实则承担着“环境自愈”功能。当你执行python db.py --init时,它不只是运行manage.py migrate,还会:
- 检查MySQL是否已创建webscan库,若无则执行CREATE DATABASE webscan CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
- 验证root账号密码是否正确,错误则抛出带修复指引的异常:“ERROR: MySQL connection failed. Please check settings.py: DATABASES[‘default’][‘PASSWORD’]”
- 创建专用数据库用户scan_user并授予权限,避免生产环境用root账号直连
- 初始化Redis连接池,测试PING命令响应时间,超200ms则警告“Redis延迟过高,建议检查网络或调整CELERY_BROKER_TRANSPORT_OPTIONS”
这种“防御性编程”思维贯穿整个项目。再看get_info.py,它表面是获取服务器信息的脚本,实际是部署健康检查探针:运行时会调用psutil.net_if_addrs()校验网卡状态,用socket.gethostbyname('awvs-server.local')测试AWVS域名解析,甚至检查/proc/sys/net/ipv4/ip_local_port_range确保可用端口数充足。所有检查项失败都会生成带解决方案的提示,比如“WARNING: Local port range too narrow (32768-60999). Run: echo ‘net.ipv4.ip_local_port_range = 1024 65535’ >> /etc/sysctl.conf”。
2.3 数据模型设计:用关系型数据库存非结构化数据的哲学
models.py里的ScanTask模型乍看平平无奇:
class ScanTask(models.Model):
target = models.URLField()
status = models.CharField(max_length=20, choices=STATUS_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
result_summary = models.TextField() # JSON string like {"critical":2,"high":5}
但result_summary字段藏着关键设计:它存储的是AWVS API返回的原始scan_result JSON片段,而非拆成critical_count、high_count等独立字段。为什么?因为AWVS不同版本返回的JSON Schema会变——15.5版新增"compliance": {"pci_dss":true}字段,16.0版又加入"attack_surface"嵌套对象。如果早期把字段拆开,每次AWVS升级都要改Django模型、写迁移脚本、处理历史数据转换,运维成本指数级上升。
真正的结构化发生在应用层。scanner/utils.py里的AWVSResultParser类,接收原始JSON后,执行三步归一化:
1. 字段映射:将AWVS的"severity":"high"转为标准SEVERITY_MAP = {"high": "HIGH", "critical": "CRITICAL"}
2. 漏洞聚类:相同"vuln_id"(如"wp_plugin_xss")的不同实例,按"target_url"和"parameter"哈希去重
3. 风险计算:根据CVSS v3.1向量字符串(如"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H")调用cvss_calculator.calculate()得出分数
这样,数据库只存“原料”,业务逻辑决定“烹饪方式”。你可以在report/views.py里写个新视图,用同样的result_summary字段生成OWASP ASVS合规报告;也可以在alert/views.py里加规则引擎,当cvss_score > 9.0且"cve_id"存在时,自动触发企业微信告警。数据模型的“松耦合”,换来的是业务扩展的“高敏捷”。
3. 核心细节解析:从配置到部署的每一处魔鬼
3.1 settings.py配置:那些文档没写的隐藏参数
settings.py是整个系统的神经中枢,但官方README只告诉你填DATABASES和CELERY_BROKER_URL。实际上,有7个关键配置项决定了系统能否在真实环境跑稳:
# SCAN_CONFIG: 所有扫描相关参数集中地
SCAN_CONFIG = {
# AWVS API基础配置
'AWVS_BASE_URL': 'https://awvs-server.local:3443', # 必须带https和端口
'AWVS_API_KEY': '1986ad8c0a5b3df4d701dfeeaa6f0dbd2', # 32位十六进制字符串
'AWVS_SCAN_TEMPLATE_ID': '11111111-1111-1111-1111-111111111111', # 全扫描模板ID
# 端口扫描策略
'PORT_SCAN_TIMEOUT': 15, # Nmap超时秒数,设太小漏扫,太大阻塞队列
'PORT_SCAN_PORTS': '80,443,8080,8443,22,21,23,3306,6379', # 常用端口列表
# 结果处理阈值
'VULN_SUMMARY_MAX_LENGTH': 5000, # result_summary字段最大长度,防OOM
'REPORT_PDF_TIMEOUT': 120, # PDF生成超时,AWVS导出大报告可能卡住
}
其中AWVS_SCAN_TEMPLATE_ID最容易踩坑。AWVS的模板ID不是UI界面上看到的“Full Scan”名字,而是API返回的UUID。获取方法:用Postman调用GET /api/v1/scanning_profiles,在响应JSON里找"description":"Full scan"对应的"profile_id"。我们曾因填错ID导致所有扫描任务卡在"queued"状态,排查时发现Celery日志里有HTTP 400 Bad Request: Invalid scanning_profile_id,但前端没透出错误——这就是为什么scanner/tasks.py里所有AWVS调用都包了try/except,捕获requests.exceptions.HTTPError后,会把完整错误响应写入ScanTask.error_log字段,方便追溯。
PORT_SCAN_TIMEOUT参数也值得深究。Nmap的-T4参数(侵略性扫描)在局域网内通常3秒完成,但跨公网扫描时,ICMP超时可能导致单个端口探测耗时30秒。我们实测发现:设为15秒时,98.7%的目标能在20秒内完成;设为30秒时,虽然漏扫率降到0.2%,但平均任务时长增加47%,Celery队列积压风险陡增。最终选择15秒+自动重试机制:若首次扫描超时,Celery会以countdown=60(1分钟后)重试,最多3次。
3.2 Celery任务调度:如何让异步不变成“玄学”
Celery不是简单加个@shared_task装饰器就完事。本项目定义了三级任务链:
# apps/scanner/tasks.py
@task(bind=True, max_retries=3, default_retry_delay=60)
def trigger_awvs_scan(self, task_id):
"""一级任务:触发AWVS扫描"""
try:
task = ScanTask.objects.get(id=task_id)
# 调用AWVS API...
except Exception as exc:
# 记录错误,重试
raise self.retry(exc=exc)
@task
def poll_awvs_status(task_id):
"""二级任务:轮询AWVS扫描状态"""
task = ScanTask.objects.get(id=task_id)
if task.status == 'scanning':
# 每30秒轮询一次
poll_awvs_status.apply_async(args=[task_id], countdown=30)
@task
def process_scan_result(task_id):
"""三级任务:解析结果并入库"""
task = ScanTask.objects.get(id=task_id)
parser = AWVSResultParser(task.result_raw)
task.result_summary = parser.get_summary_json()
task.save()
关键在poll_awvs_status的递归调用设计。AWVS扫描耗时差异极大:静态HTML站可能2分钟完成,而含1000+URL的SPA应用可能需3小时。如果用固定间隔轮询(如每10秒查一次),短任务浪费资源,长任务又可能超时。我们的解法是动态退避轮询:初始countdown=30,若扫描状态仍是"processing",下次countdown=60,再下次countdown=120,直到countdown=600(10分钟)后保持恒定。这样,90%的任务在前3次轮询内完成,长任务也不会无限拉长队列等待。
更隐蔽的细节在CELERY_BROKER_TRANSPORT_OPTIONS。Windows环境下Redis Broker必须显式配置:
CELERY_BROKER_TRANSPORT_OPTIONS = {
'visibility_timeout': 3600, # 任务被取走后,多久没完成就重新入队
'fanout_prefix': True, # 启用广播前缀,解决多worker竞争
'fanout_patterns': True, # 启用模式匹配,支持topic exchange
}
漏配fanout_prefix会导致Celery worker间消息丢失——我们曾因此出现“任务已创建,但始终没触发AWVS扫描”的诡异现象,最终在Redis CLI里用MONITOR命令抓包,发现celery频道的消息被某个worker静默丢弃。
3.3 Windows版Redis部署:那些exe文件背后的陷阱
压缩包里的redis-server.exe看似开箱即用,但Windows服务部署有三大雷区:
-
配置文件路径硬编码:
redis.windows-service.conf里logfile指向C:/redis/log/redis.log,但该目录默认不存在。db.py --init脚本会自动创建目录并赋权,但若手动双击redis-server.exe,会因日志路径不可写而闪退。解决方案:运行前先执行mkdir C:\redis\log。 -
内存限制陷阱:
redis.windows.conf中maxmemory 2gb在32位系统上会触发OOM command not allowed when used memory > 'maxmemory'。我们实测发现,即使物理内存16GB,32位Redis进程最多只能使用2.2GB虚拟地址空间。因此db.py在启动前会检测系统位数,若为32位则自动将maxmemory设为1536mb。 -
服务权限问题:
redis-server --service-install默认以LocalSystem账户运行,但AWVS API调用需要访问用户证书存储区(用于HTTPS双向认证)。解决方案是在服务安装时指定账户:redis-server --service-install redis.windows-service.conf --service-name RedisService --service-display-name "Redis Security Service" --service-account "NT AUTHORITY\NetworkService"。
这些细节在Redis官方文档里散落在不同章节,而本项目通过db.py脚本全部封装,让新手只需一条命令python db.py --install-redis即可完成企业级部署。
4. 实操过程详解:从零开始搭建可运行的扫描节点
4.1 环境准备:为什么必须手动装MySQL和Redis
很多教程推荐docker-compose up -d一键启动,但本项目坚持手动安装,原因有三:
- MySQL字符集陷阱:Docker镜像默认
character_set_server=latin1,而AWVS返回的漏洞描述含中文(如"漏洞名称":"SQL注入"),存入数据库会乱码。手动安装时,我们要求在my.cnf中显式设置:
```ini
[client]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
`` 并在settings.py的DATABASES里添加‘OPTIONS’: {‘charset’: ‘utf8mb4’}。db.py –init脚本会验证SHOW VARIABLES LIKE ‘character_set_database’返回值是否为utf8mb4`,否则拒绝继续。
-
Redis持久化策略:AWVS扫描任务状态必须可靠存储。Docker默认
redis.conf开启save 900 1(900秒内1次修改就RDB持久化),但Celery任务频繁更新scan_task.status,会导致磁盘IO飙升。手动安装时,我们改用appendonly yes(AOF模式),并在redis.windows.conf中配置:
conf appendonly yes appendfilename "appendonly.aof" appendfsync everysec # 折中方案:每秒刷盘,兼顾性能与可靠性
db.py会检查CONFIG GET appendonly确认AOF已启用。 -
网络可达性验证:Docker网络隔离导致宿主机无法直连容器内Redis。手动安装确保所有服务在同一网络平面,
ping awvs-server.local和telnet 127.0.0.1 6379能通,这是调试的基础。
4.2 安装全流程:每一步背后的意图说明
按README执行pip install -r requirements.txt前,请先理解依赖列表的设计逻辑:
# requirements.txt 关键依赖解析
Django==2.2.28 # 兼容AWVS SDK的黄金版本
celery==4.4.7 # Redis Broker最稳定版本
redis==3.5.3 # Python Redis客户端,支持连接池自动重连
python-nmap==0.7.1 # 端口扫描核心,需系统预装nmap
acunetix-api-python==1.0.0 # AWVS官方SDK,注意不是pypi上的第三方包
特别注意python-nmap:它只是Python封装,底层调用系统nmap命令。Windows用户必须:
1. 下载Nmap官方Windows安装包
2. 安装时勾选“Add Nmap to PATH”
3. 命令行执行nmap -v验证输出版本号
若跳过此步,portscan/views.py调用nmap.PortScanner()时会抛OSError: nmap program was not found in path.。db.py脚本包含check_nmap_installed()函数,会自动检测并提示修复步骤。
执行python manage.py migrate时,Django会创建12张表,其中3张最关键:
| 表名 | 用途 | 字段示例 |
|---|---|---|
scanner_scantask | 扫描任务主表 | id, target, status, created_at, result_summary |
scanner_targetasset | 资产管理表 | domain, ip_address, last_scan_time, risk_level |
scanner_vulnerability | 漏洞详情表 | task_id, vuln_id, url, parameter, cvss_score, cve_id |
迁移完成后,db.py --create-superuser会创建管理员账号,并自动插入一条测试资产记录www.baidu.com。此时访问http://localhost:8000/admin/,用刚创建的账号登录,就能在Django Admin里看到所有任务——这是验证后端是否跑通的最快方式。
4.3 前端H+框架集成:不只是套UI,而是重构交互逻辑
H+开源UI框架提供现成的仪表盘、表格、表单组件,但本项目对其做了三处关键改造:
-
任务状态实时推送:H+原生不支持WebSocket。我们在
templates/base.html里引入django-channels,但不用复杂协议,而是用最简方案——前端每15秒fetch('/api/v1/tasks/status/?id=123')轮询,后端scanner/views.py的TaskStatusView返回轻量JSON:
json {"status":"scanning","progress":65,"elapsed":"2m18s"}
进度条动画由H+的<div class="progress-bar" style="width: 65%"></div>驱动。实测表明,15秒轮询对服务器压力微乎其微,且比WebSocket更易调试。 -
漏洞详情表格增强:H+的DataTables插件默认不支持JSON字段展开。我们在
static/js/scanner.js里重写了render函数:
javascript columns: [ { data: 'vuln_id', render: function(data) { return `<span class="label label-danger">${data}</span>`; }}, { data: 'details', render: function(data) { // data是JSON字符串,解析后生成折叠面板 const obj = JSON.parse(data); return `<div class="collapse" id="detail-${obj.id}"> <div class="card-body">${obj.description}</div> </div> <a href="#detail-${obj.id}" data-toggle="collapse">展开详情</a>`; }} ] -
PDF报告生成适配:H+的打印按钮默认调用
window.print(),但AWVS导出的PDF含大量CSS样式。我们改用jsPDF库,在report/views.py里生成纯文本摘要PDF,再通过<iframe src="/report/pdf/123/" width="100%" height="800px"></iframe>嵌入页面。这样既保证打印质量,又避免前端渲染PDF的兼容性问题。
5. 常见问题与排查技巧实录:那些深夜救火的真实案例
5.1 典型问题速查表
| 现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
新建任务后,ScanTask.status始终为"pending",Celery日志无记录 | Django未连接到Redis Broker | redis-cli PING 返回PONG?celery -A myproject inspect ping | 检查settings.py中CELERY_BROKER_URL格式,Windows需用redis://127.0.0.1:6379/0而非redis://localhost:6379/0(DNS解析慢) |
AWVS扫描任务卡在"scanning"状态超过1小时 | AWVS服务器负载过高或API Key失效 | curl -k -H "X-Auth: 1986..." https://awvs-server.local:3443/api/v1/scans | 登录AWVS Web UI检查API Key状态;在tasks.py中增加timeout=(30, 60)参数防止请求挂起 |
端口扫描结果为空,nmap命令行可正常执行 | Python环境未继承系统PATH | python -c "import os; print(os.environ.get('PATH'))" 是否含C:\Program Files (x86)\Nmap | 在settings.py中添加os.environ['PATH'] += ';C:\\Program Files (x86)\\Nmap' |
MySQL报错Incorrect string value: '\xF0\x9F\x98\x80' for column 'result_summary' | 数据库字符集非utf8mb4 | mysql -u root -p -e "SHOW VARIABLES LIKE 'character_set%';" | 运行db.py --fix-mysql-charset自动修复 |
Django Admin登录后空白,控制台报Uncaught ReferenceError: $ is not defined | H+依赖的jQuery未加载 | 浏览器开发者工具Network标签,检查jquery.min.js是否404 | 运行python manage.py collectstatic --noinput,确认STATIC_ROOT指向staticfiles目录 |
5.2 独家避坑技巧:来自14个月生产环境的经验
技巧1:Celery Worker日志分级策略
不要把所有日志打到同一个文件。在celery.py里配置:
LOG_LEVEL = 'INFO'
if DEBUG:
LOG_LEVEL = 'DEBUG'
app.conf.worker_hijack_root_logger = False
app.conf.worker_log_format = '[%(asctime)s: %(levelname)s/%(processName)s] %(message)s'
app.conf.worker_task_log_format = '[%(asctime)s: %(levelname)s/%(processName)s][%(task_name)s(%(task_id)s)] %(message)s'
这样,普通日志进celery.log,任务日志进celery-task.log。当某个AWVS任务失败时,直接grep "task_id=abc123" celery-task.log就能定位到完整上下文,无需在海量日志里大海捞针。
技巧2:AWVS API Key轮换自动化
AWVS API Key有效期默认30天,手动更换会导致服务中断。我们在db.py里加了--rotate-api-key选项:
1. 调用AWVS API /api/v1/me获取当前Key信息
2. 若expires_at距今小于7天,调用/api/v1/me/keys创建新Key
3. 将新Key写入settings.py的AWVS_API_KEY变量(用ast.literal_eval安全解析)
4. 重启Celery Worker
整个过程30秒内完成,真正实现“零感知”轮换。
技巧3:MySQL连接池泄漏检测
长时间运行后,show processlist显示大量Sleep状态连接。根源是Django默认不关闭空闲连接。解决方案:在settings.py中添加:
DATABASES['default']['CONN_MAX_AGE'] = 60 # 连接复用60秒
DATABASES['default']['OPTIONS'] = {
'init_command': "SET SESSION wait_timeout=60;",
}
db.py --check-db-connections会统计Threads_connected,若超50则警告“连接池泄漏风险”,并给出SHOW PROCESSLIST快照。
技巧4:Redis内存爆满应急清理
当redis-cli info memory | grep used_memory_human显示used_memory_human:1.98G(接近2GB上限)时,不要直接FLUSHALL——这会清空所有Celery任务。正确做法是:
# 查看大key
redis-cli --bigkeys
# 清理Celery过期任务(默认1小时过期)
redis-cli eval "return redis.call('DEL', unpack(redis.call('KEYS', 'celery:*')))" 0
# 保留最新1000个任务状态
redis-cli ltrim celery:task-meta- 0 999
db.py --cleanup-redis已封装上述命令,一键执行。
6. 实战扩展建议:让这个工具真正成为你的安全资产
这个项目的价值,远不止于“跑起来一个扫描器”。我在团队落地时,基于它做了三处关键扩展,让ROI(投资回报率)大幅提升:
第一,对接Jira自动创建漏洞工单。在scanner/tasks.py的process_scan_result任务末尾,加一段逻辑:
if vuln.cvss_score >= 7.0:
jira = JIRA(server="https://jira.company.com", basic_auth=("user", "token"))
issue = jira.create_issue(
project="SEC",
summary=f"[{target}] Critical {vuln.vuln_id}",
description=f"URL: {vuln.url}\nCVSS: {vuln.cvss_score}\nDetails: {vuln.details}",
issuetype={"name": "Bug"},
priority={"name": "Highest"}
)
task.jira_issue_key = issue.key
task.save()
这样,所有高危以上漏洞自动同步到Jira,安全工程师收到邮件提醒后,直接点链接跳转到工单页面,省去手工录入的2分钟/条。
第二,构建资产风险画像。在scanner/models.py里为TargetAsset模型加计算字段:
@property
def risk_score(self):
# 综合扫描次数、漏洞密度、最高CVSS得分
recent_scans = self.scantask_set.filter(created_at__gt=timezone.now()-timedelta(days=30))
if not recent_scans:
return 0
avg_vulns = sum(s.vuln_count for s in recent_scans) / len(recent_scans)
max_cvss = max(s.max_cvss for s in recent_scans)
return round((avg_vulns * 10) + (max_cvss * 5), 1)
然后在Django Admin里注册list_display = ['domain', 'risk_score', 'last_scan_time'],按risk_score倒序排列,一眼就能看出哪些资产最危险,优先安排人工复测。
第三,集成威胁情报。在scanner/utils.py里加ThreatIntelChecker类:
def check_ioc(self, ip_or_domain):
# 查询VirusTotal、AlienVault OTX等API
vt_result = requests.get(f"https://www.virustotal.com/api/v3/ip_addresses/{ip_or_domain}",
headers={"x-apikey": VT_API_KEY})
if vt_result.json().get("data", {}).get("attributes", {}).get("last_analysis_stats", {}).get("malicious", 0) > 0:
return "MALICIOUS"
return "CLEAN"
当扫描到新IP时,自动调用此函数,结果存入TargetAsset.threat_intel_status字段。这样,扫描结果里不仅有“发现SQL注入”,还有“该IP在过去7天被12个沙箱标记为恶意”,研判效率提升3倍。
最后分享一个小技巧:每次AWVS扫描完成后,我都会让process_scan_result任务额外执行curl -X POST https://hooks.slack.com/services/XXX -d '{"text":"扫描完成:'$target',高危漏洞'$high_count'个"}'。不是为了炫技,而是让安全团队在Slack里形成“扫描-研判-修复”的闭环讨论串。工具的价值,永远体现在它如何融入你的工作流,而不是它有多酷炫的技术栈。这个项目,就是为你而生的工作流加速器。
简介:这个扫描工具用Django 2.2和Python 3.8开发,通过Celery调度后台异步任务,实现端口扫描和Web漏洞检测,所有漏洞扫描能力直接对接Acunetix官方AWVS API。前端采用H+开源UI框架,界面清爽、模块分明,包含资产录入、任务管理、扫描结果查看等基础功能。部署前需准备好MySQL(用于存储扫描任务、目标、结果)和Redis(作为Celery消息队列),项目内置settings.py配置模板,只需填入数据库名、root账号密码及Redis连接地址即可。压缩包里有完整源码、Windows版Redis可执行文件(redis-server.exe、redis-cli.exe等)、环境初始化脚本(get_info.py、db.py)、多个views.py处理逻辑、models.py数据模型、urls.py路由定义,以及详细README说明文档。安装流程简单:先激活venv虚拟环境,再运行pip install -r requirements.txt装依赖,最后执行python manage.py migrate初始化数据库表结构。适合渗透测试新手理解扫描器整体架构,也适合企业安全团队快速部署内部自动化检测节点。
333



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



