
简介本资源是一套基于Python与Django框架实现的Web漏洞挖掘扫描系统面向网络安全初学者、毕业设计学生及渗透测试入门实践者聚焦Web常见安全风险如SQL注入的自动化识别与可视化分析。系统采用模块化设计涵盖主题爬虫信息采集、漏洞探测高/中/低风险分级判定和SQL注入测试三大核心功能并通过Web界面生成检测报告助力快速定位与复现问题。压缩包共461个文件含33个核心Python源码含Django视图、模型与扫描逻辑、53个JS前端交互脚本、194张UI截图与流程图PNG/GIF、10个HTML模板页、7个SQLite数据库文件含测试数据以及CSS样式库如layui.css、layer.css等和少量演示文档PPTX/DOCX整体大小为19.16MB。目前已有500人学习下载提供完整可运行项目结构、前后端分离实现细节及典型漏洞测试用例适合用于课程设计、毕设开发或安全工具二次开发参考。1. 从“人狗大作战”到企业级安全为什么Django开发者必须懂漏洞挖掘最近在社区里看到一个挺有意思的帖子有人在问“人狗大作战python代码2023”的实现。抛开这个游戏本身不谈这背后反映了一个非常普遍的现象大量开发者尤其是刚入门的Python爱好者正热情地投入到各种项目的构建中从游戏、爬虫到数据分析。而Django作为Python生态中最成熟、国内使用也极为广泛的全栈Web框架自然成为了许多人的首选。无论是新手照着“django教程”创建第一个app还是老手用“vite django”搞前后端分离或是尝试“django接入deepseek”这类AI应用Django的便捷性让功能实现变得前所未有的简单。但便捷往往伴随着风险。当你用python manage.py runserver轻松跑起一个服务或者按照“python安装详细步骤”配好环境在“vscode配置python环境”后开始愉快地敲代码时一个严峻的问题就被忽视了你构建的Web应用安全吗我见过太多项目业务逻辑复杂界面炫酷用的也是最新的“python3”和Django版本但一谈到安全基本就是“裸奔”状态。大家热衷于搜索“python cc攻击源码”来测试别人的服务器却很少审视自己的代码是否存在同样的漏洞关心“python安装numpy库的方法”来跑模型却对Django中一个不当的查询操作可能引发的数据泄露一无所知。这就是我想讨论的核心基于Python和Django的Web漏洞挖掘不是一个只有安全专家才需要关注的玄学而是每一个Django开发者必备的生存技能。它不是在攻击而是在防御。你需要像攻击者一样思考才能构建出真正坚固的防线。本文不会提供任何攻击性代码如“免费python源码大全”里可能混杂的那些而是从一个资深开发兼安全审计者的角度带你系统性地审视一个Django项目可能存在的脆弱点并分享如何利用Python的强大能力将它们一一挖出并修复。无论你是正在“python入门”还是已经用Django做过几个项目这篇文章都能帮你把应用的安全水位提升一个档次。2. 环境不是跑通就行漏洞挖掘视角下的Django项目初始化很多人觉得环境配置是小事照着“python下载安装教程”操作就行。但一个不严谨的初始环境本身就是第一个漏洞。我们从漏洞挖掘的视角重新走一遍这个过程。2.1 虚拟环境与依赖管理被忽视的供应链攻击入口你的第一步肯定是安装Python。但请注意从“python下载”的官网源获取安装包是基本准则避免使用来路不明的第三方打包版本。安装后绝不建议在系统全局Python中直接pip install django。你必须使用虚拟环境。# 使用venv创建隔离环境是必须的而不是可选项 python -m venv venv_django_sec # 激活环境 # Windows: venv_django_sec\Scripts\activate # Linux/Mac: source venv_django_sec/bin/activate为什么强调这个因为依赖漏洞是当前最主流的攻击方式之一。在虚拟环境中你可以为当前项目精确锁定所有包的版本。接下来不要直接pip install django而是先创建一个requirements.txt文件并优先使用pip-tools或poetry这类工具来管理。# requirements.in Django4.2, 5.0 # 明确主版本范围避免自动升级到可能不兼容的大版本 psycopg2-binary # 如果使用PostgreSQL pillow # 处理图片时常用然后编译生成精确版本锁文件pip-compile requirements.in生成的requirements.txt会包含所有次级依赖及其哈希值。部署时使用pip install -r requirements.txt。这样做的好处是你可以定期使用pip-audit或safety等工具扫描requirements.txt快速发现已知漏洞的依赖包。注意很多教程会教你用pip freeze requirements.txt这在早期可以但它会混入所有系统已安装的包导致依赖树不纯净。使用pip-compile是从requirements.in这个“声明文件”生成更清晰、更安全。2.2 项目配置从settings.py开始埋下安全种子使用django-admin startproject sec_project .创建项目后settings.py是你的安全配置中心。很多开发者会直接从旧项目复制或者只修改数据库连接和ALLOWED_HOSTS这远远不够。1. 密钥管理绝不能硬编码Django的SECRET_KEY用于加密签名和会话。它绝不能出现在代码仓库中。第一步就是将它移出settings.py。# settings.py import os from pathlib import Path from dotenv import load_dotenv # 使用python-dotenv load_dotenv() # 从项目根目录的.env文件加载环境变量 BASE_DIR Path(__file__).resolve().parent.parent SECRET_KEY os.environ.get(SECRET_KEY) # 从环境变量读取 if not SECRET_KEY: raise ValueError(SECRET_KEY 环境变量未设置)然后在项目根目录创建.env文件并写入SECRET_KEY你的超长随机字符串。务必在.gitignore中添加.env。生产环境则应使用服务器环境变量或专门的密钥管理服务如Vault。2. 调试模式与允许主机开发与生产的生死线# 错误示例为了方便生产环境也设为True DEBUG True # 正确做法根据环境变量判断 DEBUG os.environ.get(DJANGO_DEBUG, False).lower() true ALLOWED_HOSTS [] # 生产环境必须明确指定 # ALLOWED_HOSTS [.yourdomain.com, your-server-ip]DEBUGTrue在生产环境是致命错误。它会暴露完整的错误追踪信息、配置详情甚至执行任意代码的漏洞。必须通过环境变量严格控制。ALLOWED_HOSTS为空时Django只会允许localhost生产环境必须配置。3. 数据库连接连接池与SSL不要只用简单的字典配置。对于PostgreSQL考虑连接池和强制SSLDATABASES { default: { ENGINE: django.db.backends.postgresql, NAME: os.environ.get(DB_NAME), USER: os.environ.get(DB_USER), PASSWORD: os.environ.get(DB_PASSWORD), HOST: os.environ.get(DB_HOST), PORT: os.environ.get(DB_PORT, 5432), OPTIONS: { sslmode: require, # 强制SSL连接防止中间人攻击窃听数据库流量 connect_timeout: 5, }, CONN_MAX_AGE: 300, # 启用连接复用避免频繁建立连接的开销和潜在风险 } }4. 静态文件与媒体文件权限控制确保生产环境如Nginx正确代理静态文件Django本身不应用来处理。特别注意媒体文件用户上传的权限。千万不要使用django.views.static.serve视图在生产环境提供用户上传的文件这会导致目录遍历漏洞。应该使用专门的存储后端如S3或配置Web服务器直接提供并严格校验文件类型和路径。2.3 第一个安全中间件CSP与安全头在MIDDLEWARE列表中添加安全相关的中间件顺序很重要MIDDLEWARE [ django.middleware.security.SecurityMiddleware, # Django内置安全头中间件必须启用 # ... 其他中间件 ]仅启用SecurityMiddleware还不够它默认提供一些基础HTTP头。我们还需要更严格的配置在settings.py末尾添加# 安全头强化 SECURE_BROWSER_XSS_FILTER True SECURE_CONTENT_TYPE_NOSNIFF True X_FRAME_OPTIONS DENY # 防止点击劫持 # HTTPS相关生产环境启用 # SECURE_SSL_REDIRECT True # 将所有HTTP请求重定向到HTTPS # SESSION_COOKIE_SECURE True # 仅通过HTTPS传输会话Cookie # CSRF_COOKIE_SECURE True # 仅通过HTTPS传输CSRF Cookie # 内容安全策略 (CSP) - 需要根据项目资源调整这是强力XSS防御手段 CSP_DEFAULT_SRC (self,) CSP_SCRIPT_SRC (self, unsafe-inline) # 谨慎使用unsafe-inline最好消除内联脚本 CSP_STYLE_SRC (self, unsafe-inline)CSP内容安全策略是防御XSS的利器但配置不当会阻断正常资源加载。建议在开发后期逐步实施。3. 深入ORM层SQL注入与数据暴露的隐形战场Django的ORM对象关系映射以其“能防止SQL注入”而闻名。这导致很多开发者放松了警惕认为用了ORM就高枕无忧。实际上ORM只是将风险转移了不当使用依然会导致严重漏洞。3.1 当ORM“防注入”失效时常见危险模式危险操作1使用extra()或RawSQL()时字符串拼接# 危险用户输入的user_input直接拼接进SQL from django.db.models.expressions import RawSQL user_input request.GET.get(order_by, id) # 如果user_input是 id; DROP TABLE auth_user --后果不堪设想 queryset MyModel.objects.all().extra(select{val: fsome_column * {user_input}}) # 安全做法如果必须使用原生SQL使用参数化查询 queryset MyModel.objects.raw(SELECT * FROM myapp_mymodel WHERE id %s, [user_input])extra()和RawSQL()是ORM提供的“逃生舱”用于执行复杂SQL。但一旦将用户输入直接拼接到SQL字符串中所有防护瞬间归零。必须使用参数化查询让数据库驱动来处理参数。危险操作2Q()对象中的动态字段名有时我们需要动态构造查询条件。from django.db.models import Q filter_field request.GET.get(field) # 比如 username filter_value request.GET.get(value) # 比如 admin # 危险动态字段名如果来自用户输入可能导致异常或信息泄露 query_dict {filter_field: filter_value} queryset User.objects.filter(**query_dict) # 更危险的做法用字符串构造Q对象 q_object Q(**{f{filter_field}__icontains: filter_value})这里filter_field如果用户可控攻击者可以传入is_superuserTrue来探测管理员账户或者传入不存在的字段名引发错误从错误信息中获取数据库结构。解决方案是白名单校验ALLOWED_FILTER_FIELDS [username, email, date_joined] if filter_field not in ALLOWED_FILTER_FIELDS: filter_field username # 或返回错误 query_dict {filter_field: filter_value}危险操作3聚合与注解中的用户输入from django.db.models import Count, F user_input request.GET.get(calc) # 例如 ‘price’ * ‘quantity‘ # 绝对不要这样做 # queryset Product.objects.annotate(totaleval(user_input))绝对禁止使用eval()处理用户输入。任何计算逻辑都应该在代码中明确定义。3.2 批量操作与信号性能与数据一致性的陷阱Django的bulk_create、bulk_update以及update()方法非常高效但它们会绕过模型的save()方法因此也不会触发模型定义的save()信号post_save,pre_save。# 假设User模型有一个post_save信号用于创建用户配置档案 from django.db.models.signals import post_save from django.dispatch import receiver receiver(post_save, senderUser) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(userinstance) # 使用bulk_create创建用户 User.objects.bulk_create([User(usernameu1), User(usernameu2)]) # 问题这两个用户的Profile永远不会被创建这可能导致数据不一致。如果你依赖信号来完成关键业务逻辑如审计日志、数据衍生、通知那么批量操作后必须手动执行这些逻辑。从安全审计角度看这也意味着通过bulk_update恶意修改数据可能绕过某些基于信号的审计或验证。3.3 敏感数据泄露序列化与日志记录1. QuerySet序列化直接将QuerySet或模型实例传递给模板或者在API中不小心序列化过多字段会导致敏感信息泄露。# views.py def user_list(request): users User.objects.all().values(id, username, email, is_superuser, last_login) return JsonResponse(list(users), safeFalse) # 泄露了is_superuser和last_login必须严格定义序列化器如Django REST Framework的Serializer或手动控制输出的字段字典。2. 日志中的敏感信息Django的数据库查询日志、错误邮件中可能包含完整的SQL语句和参数。# settings.py 中错误的日志配置 LOGGING { version: 1, disable_existing_loggers: False, handlers: { console: { level: DEBUG, # 在生产环境记录DEBUG日志是危险的 class: logging.StreamHandler, }, }, loggers: { django.db.backends: { level: DEBUG, # 这会记录所有SQL语句包括带参数的 handlers: [console], }, }, }生产环境应将django.db.backends的级别设为INFO或WARNING。对于错误报告可以考虑使用django.views.decorators.debug.sensitive_post_parameters和sensitive_variables装饰器来标记敏感参数防止它们被记录。4. 视图与业务逻辑漏洞滋生的核心温床视图是处理用户请求的核心也是逻辑漏洞和常见Web漏洞如越权、CSRF、SSRF的高发区。4.1 权限校验的深度误区不仅仅是login_requiredlogin_required装饰器只检查用户是否登录不检查用户是否有权访问特定对象。这就是典型的越权漏洞Broken Object Level Authorization, BOLA。# 漏洞示例用户可查看/修改任意订单 from django.contrib.auth.decorators import login_required login_required def order_detail(request, order_id): order Order.objects.get(idorder_id) # 直接根据ID获取未校验所属用户 return render(request, order_detail.html, {order: order}) login_required def update_order(request, order_id): order Order.objects.get(idorder_id) order.status request.POST[status] order.save() # 任何登录用户都能修改任意订单修复方案是在每次对象访问时进行权限校验。Django提供了django.contrib.auth.mixins中的类视图Mixin但对于函数视图需要手动处理from django.shortcuts import get_object_or_404 login_required def order_detail(request, order_id): # 使用get_object_or_404并添加过滤条件 order get_object_or_404(Order, idorder_id, userrequest.user) # 或者更通用的检查自定义权限 # order get_object_or_404(Order, idorder_id) # if not request.user.has_perm(app.view_order, order): # raise PermissionDenied return render(request, order_detail.html, {order: order})对于复杂权限推荐使用像django-guardian这样的第三方库它提供了基于每个对象的权限控制。4.2 脆弱的CSRF防护理解豁免与AJAX请求Django的CSRF中间件默认提供良好的防护。但有几个常见场景会导致防护失效1. 错误地使用csrf_exemptfrom django.views.decorators.csrf import csrf_exempt csrf_exempt # 危险移除了整个视图的CSRF保护 def api_webhook(request): # 处理来自第三方的Webhook pass如果你确认某个端点需要被外部服务调用如支付回调、Webhook且无法携带CSRF token那么豁免是合理的。但你必须确保该端点不执行任何依赖于用户会话状态的特权操作并且最好有其他认证方式如签名、API密钥。更安全的做法是为这类API单独设计不使用基于Cookie的会话认证。2. AJAX请求忘记携带CSRF Token对于使用fetch或axios的AJAX POST请求需要手动设置。// 前端JavaScript const csrftoken document.querySelector([namecsrfmiddlewaretoken]).value; fetch(/api/update/, { method: POST, headers: { X-CSRFToken: csrftoken, // 关键设置自定义头 Content-Type: application/json, }, body: JSON.stringify(data) })Django会检查X-CSRFToken请求头。如果前端是单页应用SPA且与Django后端分离部署可能需要调整CSRF Cookie的SameSite属性并确保前端能正确读取和发送Token。4.3 服务器端请求伪造SSRF内部服务暴露的灾难SSRF攻击诱使服务器向内部网络发起请求攻击内网服务。Django应用中任何允许用户控制URL并发起网络请求的功能点都是风险点。# 漏洞示例一个简单的“网页预览”或“图片代理”功能 import requests from django.http import HttpResponse def fetch_url(request): url request.GET.get(url) # 用户传入任意URL try: resp requests.get(url, timeout5) return HttpResponse(resp.content, content_typeresp.headers.get(content-type)) except: return HttpResponse(Error)攻击者可以传入urlhttp://169.254.169.254/latest/meta-data/AWS元数据服务或urlfile:///etc/passwd来读取服务器敏感信息。甚至攻击内网的Redis、数据库等未授权服务。防御措施白名单校验如果功能允许只允许访问特定的、已知安全的域名。ALLOWED_DOMAINS [example.com, trusted-cdn.com] parsed_url urlparse(url) if parsed_url.netloc not in ALLOWED_DOMAINS: raise SuspiciousOperation(Domain not allowed)禁用危险协议使用urlparse解析禁止file://、gopher://、dict://等协议。if parsed_url.scheme not in (http, https): raise SuspiciousOperation(Scheme not allowed)使用受限的解析器/客户端使用只解析域名不解析IP的库或者使用一个配置了严格限制的HTTP客户端如设置allow_redirectsFalse禁用对私有IP的访问。网络层隔离将应用服务器部署在独立的网络分区限制其出站连接能力。4.4 不安全的直接对象引用IDOR与信息泄露除了前面提到的越权IDOR还体现在使用可预测的、顺序的ID作为资源标识符。例如用户订单ID为1001攻击者尝试访问1000、1002等可能看到其他用户的订单。虽然通过权限校验可以防御但使用不可预测的标识符如UUID作为主键或资源标识符可以增加攻击难度并避免通过ID推测业务量等信息。# models.py import uuid from django.db import models class Order(models.Model): id models.UUIDField(primary_keyTrue, defaultuuid.uuid4, editableFalse) # ... 其他字段在API或URL中暴露/orders/550e8400-e29b-41d4-a716-446655440000/这样的UUID远比/orders/12345/安全。5. 模板与前端XSS与客户端漏洞的最后一道防线即使后端逻辑严密一个不安全的模板也可能让所有努力前功尽弃。Django模板系统默认开启了自动HTML转义这是对抗XSS的主要武器但并非万能。5.1 自动转义的“安全区”与“危险区”!-- 假设 context {user_input: scriptalert(1)/script} -- p{{ user_input }}/p !-- 安全会被转义为 lt;scriptgt;alert(1)lt;/scriptgt; -- p{{ user_input|safe }}/p !-- 危险标记为safe脚本会执行 --|safe过滤器告诉Django“这个字符串是安全的不用转义”。只有在你百分之百确信该字符串不包含任何用户可控的、未经验证的输入时才能使用。常见的错误是将从数据库读取的、由管理员录入的“富文本内容”直接使用|safe输出而管理员后台可能存在XSS漏洞导致内容被污染。对于需要渲染富文本如博客文章的场景应该使用一个严格的HTML清理库如bleach而不是|safe。# 在视图或自定义模板过滤器中 import bleach allowed_tags bleach.sanitizer.ALLOWED_TAGS [p, br, div, span, img] allowed_attrs bleach.sanitizer.ALLOWED_ATTRIBUTES allowed_attrs[img] [src, alt, title] cleaned_html bleach.clean(user_html, tagsallowed_tags, attributesallowed_attrs)然后在模板中{{ cleaned_html|safe }}。5.2 JavaScript数据注入与JSON安全在模板中内嵌JSON数据供前端JavaScript使用是常见做法但处理不当会引发XSS。!-- 危险做法 -- script var userData {{ user_data_json|safe }}; // 如果user_data_json包含/script或控制字符会破坏脚本 /script !-- 仍然危险的做法 -- script var userData JSON.parse({{ user_data_json|escapejs }}); // escapejs 只转义了少数字符对于JSON字符串来说不够 /script正确做法是使用json_script模板过滤器{{ user_data_json|json_script:user-data }}这会在页面中生成一个script iduser-data typeapplication/json.../script标签其中的JSON被正确转义。然后前端通过以下方式安全获取var userData JSON.parse(document.getElementById(user-data).textContent);5.3 点击劫持与CSP配置强化点击劫持Clickjacking诱使用户在不知情的情况下点击恶意页面上的按钮。Django的X-FRAME-OPTIONS中间件默认设置为SAMEORIGIN可以防止页面被任意网站嵌入。但为了更全面的防护可以结合CSP的frame-ancestors指令。# settings.py # 使用 django-csp 库可以更方便地管理CSP CSP_FRAME_ANCESTORS (none,) # 禁止被任何页面嵌入比X-FRAME-OPTIONS更严格 # 或者只允许同源 # CSP_FRAME_ANCESTORS (self,)同时对于敏感操作如转账、修改密码可以在服务端增加二次确认如输入密码并在前端使用“反框架脚本”作为额外防护虽然现代浏览器中X-FRAME-OPTIONS和CSP已足够。6. 文件上传与反序列化攻击面的深度拓展文件上传功能是Web应用的高危区域而反序列化漏洞则可能带来远程代码执行的毁灭性后果。6.1 文件上传的全面防御策略一个安全的文件上传处理流程需要多层防御1. 前端验证仅辅助通过accept属性限制可选文件类型但攻击者可以轻易绕过。2. 服务端扩展名与MIME类型校验import os from django.core.files.uploadedfile import InMemoryUploadedFile from magic import Magic # 使用python-magic库进行真实文件类型检测 def handle_uploaded_file(uploaded_file: InMemoryUploadedFile): # 1. 校验扩展名白名单 allowed_extensions [.jpg, .jpeg, .png, .gif, .pdf] ext os.path.splitext(uploaded_file.name)[1].lower() if ext not in allowed_extensions: raise ValidationError(文件类型不允许。) # 2. 校验MIME类型从文件内容读取而非客户端声明 mime Magic(mimeTrue) # 需要将文件指针移动到开头 uploaded_file.seek(0) actual_mime_type mime.from_buffer(uploaded_file.read(1024)) uploaded_file.seek(0) # 重置指针 allowed_mime_types [image/jpeg, image/png, image/gif, application/pdf] if actual_mime_type not in allowed_mime_types: raise ValidationError(文件MIME类型不匹配。) # 3. 对于图片进一步验证内容使用Pillow if actual_mime_type.startswith(image/): from PIL import Image try: img Image.open(uploaded_file) img.verify() # 验证图片完整性 img.close() uploaded_file.seek(0) # 可选重置图片尺寸去除元数据 img Image.open(uploaded_file) img.thumbnail((1024, 1024)) # 限制大小 # ... 保存处理后的图片 except Exception as e: raise ValidationError(图片文件损坏或无效。) # 4. 重命名文件避免路径遍历和覆盖 import uuid new_filename f{uuid.uuid4()}{ext} # 5. 指定存储路径避免用户控制路径 save_path os.path.join(settings.MEDIA_ROOT, uploads, new_filename) # 确保目录存在 os.makedirs(os.path.dirname(save_path), exist_okTrue) with open(save_path, wb) as destination: for chunk in uploaded_file.chunks(): destination.write(chunk) return new_filename3. 内容安全扫描进阶对于企业级应用上传的文件应被送入沙箱进行静态和动态分析检测是否包含恶意代码如PDF中的JavaScript图片中的隐写恶意代码。4. 存储与访问安全文件不应存储在Web服务器的文档根目录下而应通过一个专门的视图或CDN来提供下载并在该视图中进行权限校验。对于用户上传的图片务必禁用img标签的onerror等事件属性通过CSP或HTML清理。6.2 Python反序列化漏洞的幽灵Django本身不常用pickle进行反序列化但你的应用可能会使用到其他序列化库如json、yaml或者依赖的第三方库使用了不安全的反序列化。危险案例使用yaml.load()而非yaml.safe_load()import yaml # 危险yaml.load 可以实例化任意Python类 user_config yaml.load(request.POST[config], Loaderyaml.Loader) # 安全使用 safe_load只加载基本的Python对象 user_config yaml.safe_load(request.POST[config])攻击者可以构造特殊的YAML payload导致远程代码执行RCE。例如!!python/object/apply:os.system [rm -rf /]因此处理任何来自外部的序列化数据JSON除外其标准库json.loads是安全的时必须使用安全版本yaml.safe_load、pickle绝对避免用于反序列化不可信数据。如果必须使用pickle则需要额外的完整性校验如HMAC签名。Django会话序列化器Django默认使用JSONSerializer进行会话序列化这是安全的。但如果你在settings.py中将其改为django.contrib.sessions.serializers.PickleSerializer那么会话数据就可能被恶意篡改导致RCE。永远不要在生产环境使用PickleSerializer。7. 自动化审计与持续监控将漏洞挖掘融入开发流程手动审计代码和测试是基础但可持续的安全需要自动化工具和流程的保障。7.1 静态代码分析SAST集成在CI/CD流水线中集成静态代码安全扫描工具可以在代码合并前发现问题。Bandit专门用于查找Python代码中常见安全问题的工具。pip install bandit bandit -r . -f json -o bandit-report.json它会检查是否存在硬编码密码、使用pickle、yaml.load、subprocess命令注入等风险。Safety检查项目依赖中的已知漏洞。pip install safety safety check -r requirements.txt --jsonSemgrep支持自定义规则可以编写规则来检测项目特定的不安全模式。pip install semgrep semgrep --config auto . # 使用社区规则集7.2 动态应用安全测试DAST与依赖扫描OWASP ZAP 或 Burp Suite 自动化扫描可以集成到CI中对部署的测试环境进行自动化漏洞扫描发现XSS、SQL注入在ORM误用的情况下、CSRF等问题。Trivy 或 Grype扫描Docker镜像中的操作系统包和语言依赖漏洞。trivy image your-django-app:latest7.3 依赖更新与漏洞预警使用Dependabot或Renovate这些机器人可以自动为你的仓库创建依赖更新PR特别是安全更新。订阅安全邮件列表关注Django官方安全公告、Python安全公告以及你使用的关键第三方库的发布频道。定期运行pip-auditpip install pip-audit pip-audit -r requirements.txt7.4 自定义漏洞挖掘脚本示例一个简单的ORM查询审计脚本你可以编写脚本在代码库中搜索可能存在风险的ORM使用模式。# audit_orm.py import ast import os class ORMAuditor(ast.NodeVisitor): def __init__(self): self.issues [] def visit_Call(self, node): # 查找 .extra() 调用 if isinstance(node.func, ast.Attribute): if node.func.attr extra: self.issues.append({ line: node.lineno, col: node.col_offset, type: ORM_EXTRA, msg: 发现使用 QuerySet.extra() 方法可能存在SQL注入风险请检查参数是否用户可控。 }) # 查找 RawSQL 调用 elif isinstance(node.func, ast.Name) and node.func.id RawSQL: self.issues.append({ line: node.lineno, col: node.col_offset, type: ORM_RAW_SQL, msg: 发现使用 RawSQL() 构造原生SQL请确保使用参数化查询避免字符串拼接。 }) # 查找 filter(**dict) 模式其中dict的键可能来自变量 elif node.func.attr filter: for keyword in node.keywords: if keyword.arg is None and isinstance(keyword.value, ast.Dict): # 这是一个 **kwargs 展开检查键是否是简单的字符串字面量 for key in keyword.value.keys: if not isinstance(key, ast.Constant) or not isinstance(key.value, str): self.issues.append({ line: node.lineno, col: node.col_offset, type: ORM_DYNAMIC_FILTER, msg: filter() 使用了动态字典展开键可能来自变量存在潜在的信息泄露或异常风险建议进行白名单校验。 }) self.generic_visit(node) def audit_project(root_path): for root, dirs, files in os.walk(root_path): # 忽略虚拟环境等目录 if venv in root or .git in root: continue for file in files: if file.endswith(.py): filepath os.path.join(root, file) try: with open(filepath, r, encodingutf-8) as f: tree ast.parse(f.read(), filenamefilepath) auditor ORMAuditor() auditor.visit(tree) if auditor.issues: print(f\n 文件: {filepath} ) for issue in auditor.issues: print(f 行 {issue[line]}:{issue[col]} - [{issue[type]}] {issue[msg]}) except SyntaxError as e: print(f无法解析 {filepath}: {e}) if __name__ __main__: audit_project(.)这个简单的AST抽象语法树遍历脚本可以帮你快速定位代码中潜在的ORM风险点。当然真正的企业级SAST工具会更复杂和全面。安全是一个持续的过程而不是一次性的任务。将上述的漏洞挖掘思维和自动化工具融入到你的日常开发习惯中从项目初始化、编码、代码审查到部署上线每一个环节都绷紧安全这根弦才能让你用Django构建的应用在互联网的汪洋大海中真正站稳脚跟。记住最好的漏洞挖掘就是在攻击者发现之前你自己先把它挖出来并修复掉。本文还有配套的精品资源点击获取