mcpField
S
security-django

security-django

github.com/igorwarzocha安全122101 次安装38 周前更新
代码仓库

关于 security-django

security-django 是供开发者审查 Django 应用的安全审计技能,涵盖部署设置、中间件与 CSRF,以及常见漏洞,并提供较安全的代码模式和审计命令。

主要功能

  1. 01关键设置审查
  2. 02安全中间件与 CSRF 检查
  3. 03常见漏洞模式
  4. 04更安全的代码示例
  5. 05快速审计命令
  6. 06部署加固清单

适用场景

  1. 01审查 Django 生产环境设置
  2. 02检查 CSRF 豁免与中间件
  3. 03查找注入和路径遍历风险
  4. 04检查身份验证与 DRF 权限

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/igorwarzocha/opencode-workflows --skill security-django

安装后在 Claude Code 中输入/security-django确认已加载。

附带文件scripts/scan.sh

详细介绍

针对 Django 应用的安全审计模式,涵盖关键设置、安全中间件、CSRF 保护和常见漏洞。

关键设置(settings.py)

SECRET_KEY
# ❌ CRITICAL: Hardcoded or committed
SECRET_KEY = 'django-insecure-abc123...'
SECRET_KEY = 'my-super-secret-key'

# ✓ From environment
import os
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

# ✓ Or use django-environ
import environ
env = environ.Env()
SECRET_KEY = env('SECRET_KEY')

检查: SECRET_KEY 是否存放在 .env 中,且 .env 是否已加入 .gitignore?

DEBUG
# ❌ CRITICAL: Debug in production
DEBUG = True  # Exposes full stack traces, settings, SQL queries

# ✓ Environment-controlled
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
ALLOWED_HOSTS
# ❌ CRITICAL: Accept any host
ALLOWED_HOSTS = ['*']

# ❌ HIGH: Empty in production (500 errors, but still bad)
ALLOWED_HOSTS = []

# ✓ Explicit hosts
ALLOWED_HOSTS = ['example.com', 'www.example.com']

安全中间件

必需的中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',  # MUST be first!
    # ...
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

检查: 是否包含 SecurityMiddleware,且位于靠前的位置?

安全中间件设置
# ✓ Enable these in production
SECURE_BROWSER_XSS_FILTER = True  # Deprecated but harmless
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 31536000  # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_SSL_REDIRECT = True  # Force HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

CSRF 保护

禁用 CSRF(严重)
# ❌ CRITICAL: Globally disabled
MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',  # Commented out!
]

# ❌ HIGH: Decorator abuse
@csrf_exempt
def payment_webhook(request):  # MAY be OK for webhooks with other auth
    ...

@csrf_exempt
def update_profile(request):  # MUST NOT do this!
    ...

审计: 搜索 @csrf_exempt,每处都需要有合理说明。

CSRF 可信来源(Django 4.0+)
# ❌ Too permissive
CSRF_TRUSTED_ORIGINS = ['https://*']

# ✓ Explicit
CSRF_TRUSTED_ORIGINS = ['https://example.com', 'https://admin.example.com']

常见漏洞

SQL 注入
# ❌ Raw SQL with string formatting
User.objects.raw(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute(f"DELETE FROM logs WHERE date < '{date}'")

# ✓ Parameterized
User.objects.raw("SELECT * FROM users WHERE id = %s", [user_id])
cursor.execute("DELETE FROM logs WHERE date < %s", [date])

# ✓ ORM (safe by default)
User.objects.filter(id=user_id)
命令注入
# ❌ User input in subprocess
import subprocess
subprocess.run(f"convert {user_filename} output.png", shell=True)
os.system(f"process {user_input}")

# ✓ Use arrays, avoid shell=True
subprocess.run(["convert", user_filename, "output.png"])
路径遍历
# ❌ User-controlled path
def download(request, filename):
    return FileResponse(open(f'uploads/{filename}', 'rb'))

# ✓ Validate path
import os
def download(request, filename):
    safe_name = os.path.basename(filename)
    filepath = os.path.join(settings.UPLOAD_DIR, safe_name)
    if not filepath.startswith(settings.UPLOAD_DIR):
        raise Http404()
    return FileResponse(open(filepath, 'rb'))
IDOR(不安全的直接对象引用)
# ❌ No ownership check
class DocumentView(View):
    def get(self, request, doc_id):
        doc = Document.objects.get(id=doc_id)
        return JsonResponse(doc.to_dict())

# ✓ Check ownership
class DocumentView(LoginRequiredMixin, View):
    def get(self, request, doc_id):
        doc = Document.objects.get(id=doc_id, owner=request.user)
        return JsonResponse(doc.to_dict())
缺少身份验证装饰器
# ❌ No auth required
def admin_dashboard(request):
    return render(request, 'admin/dashboard.html', {'users': User.objects.all()})

# ✓ Auth required
@login_required
@user_passes_test(lambda u: u.is_staff)
def admin_dashboard(request):
    ...

Django REST Framework

# Check DRF settings
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # ❌ SessionAuth without CSRF = vulnerable
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        # ❌ Allow any by default
        'rest_framework.permissions.AllowAny',
        # ✓ Require auth by default
        'rest_framework.permissions.IsAuthenticated',
    ],
}

快速审计命令

# Check critical settings
rg "(SECRET_KEY|DEBUG|ALLOWED_HOSTS)" settings*.py

# Find csrf_exempt usage
rg "@csrf_exempt" . -g "*.py"

# Django deployment checklist (high signal)
python manage.py check --deploy

# Find raw SQL
rg "\.raw\(|cursor\.execute\(" . -g "*.py" -A 1

# Find subprocess/os.system
rg "(subprocess\.|os\.system|os\.popen)" . -g "*.py"

# Check for missing login_required
rg "^def " views.py | head -20  # Then check which have decorators

# Find shell=True
rg "shell\s*=\s*True" . -g "*.py"

加固检查清单

  • SECRET_KEY 来自环境变量,而非硬编码
  • 生产环境中 DEBUG = False
  • 明确设置 ALLOWED_HOSTS(不使用通配符)
  • 已启用并配置 SecurityMiddleware
  • 已启用 CSRF 中间件
  • SECURE_SSL_REDIRECT = True
  • SESSION_COOKIE_SECURE = True
  • CSRF_COOKIE_SECURE = True
  • 没有未经合理说明的 @csrf_exempt
  • 所有视图都具有适当的身份验证装饰器
  • 没有使用字符串格式化的原始 SQL
  • DRF 将 IsAuthenticated 设为默认权限

评论

支持 Markdown