Python Web 开发进阶实战:安全加固实战 —— 基于 OWASP Top 10 的全栈防御体系

第一章:为什么安全不能"事后补"?

1.1 真实代价

事件 后果
XSS 窃取会话 用户账号被接管
SQL 注入 全库数据泄露(如 2017 Equifax)
IDOR(越权) A 用户读取 B 用户的医疗记录
无速率限制 暴力破解管理员密码

原则安全是功能,不是附加项。

1.2 OWASP Top 10(2021)概览

风险 本篇覆盖方案
A01: Broken Access Control RBAC + 对象级权限校验
A02: Cryptographic Failures HTTPS + 安全 JWT + 敏感字段脱敏
A03: Injection 参数化查询 + 输入验证
A04: Insecure Design 安全开发生命周期(SDL)
A05: Security Misconfiguration 安全头 + 最小权限原则
A06: Vulnerable Components 依赖扫描(safety / npm audit)
A07: Identification Failures 多因素认证 + 强密码策略
A08: Software Data Integrity 未涉及(侧重供应链)
A09: Security Logging 日志脱敏 + 异常行为告警
A10: SSRF URL 白名单 + 禁用内部协议

本篇重点解决 A01--A07、A09、A10


第二章:前端安全加固

2.1 防御 XSS(跨站脚本)

风险场景
复制代码
<!-- 危险!直接渲染用户输入 -->
<div v-html="userComment"></div>
安全方案:DOMPurify

安装:

复制代码
npm install dompurify

使用:

复制代码
// utils/sanitize.ts
import DOMPurify from 'dompurify'

export const sanitizeHTML = (html: string): string => {
  return DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong'], // 仅允许安全标签
    FORBID_ATTR: ['style', 'onerror']        // 禁用危险属性
  })
}

在组件中:

复制代码
<template>
  <div v-html="sanitizedComment"></div>
</template>

<script setup lang="ts">
import { sanitizeHTML } from '@/utils/sanitize'
const props = defineProps<{ comment: string }>()
const sanitizedComment = sanitizeHTML(props.comment)
</script>

注意 :即使使用 Vue 的 {``{ }} 插值,若后端返回 HTML 片段仍需净化。

2.2 内容安全策略(CSP)

通过 HTTP 头限制资源加载:

复制代码
# nginx.conf
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' 'unsafe-inline' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.yourdomain.com;
  frame-ancestors 'none';  # 防点击劫持
  object-src 'none';
" always;

关键指令

  • script-src:禁止内联脚本(但 Vue 开发模式需 'unsafe-inline',生产应移除)
  • connect-src:限制 AJAX 请求目标
  • frame-ancestors 'none':防止页面被嵌入 iframe

虽前端不直接操作 Cookie,但需确保后端设置正确:

复制代码
Set-Cookie: session_id=abc123; 
  HttpOnly;     ← 禁止 JS 访问
  Secure;       ← 仅 HTTPS 传输
  SameSite=Lax; ← 防 CSRF(宽松模式)
  Path=/;

注意 :JWT 通常存于 localStorage,但更推荐 HttpOnly Cookie(防 XSS 窃取)。


第三章:后端安全核心实践(Flask)

3.1 防 SQL 注入

错误做法
复制代码
# 危险!拼接 SQL
query = f"SELECT * FROM users WHERE id = {user_id}"
正确做法:参数化查询
复制代码
# SQLAlchemy ORM(自动参数化)
user = User.query.filter(User.id == user_id).first()

# 原生 SQL(显式参数)
db.session.execute(
    text("SELECT * FROM users WHERE id = :user_id"),
    {"user_id": user_id}
)

验证 :用 ' OR '1'='1 测试,应返回空或报错。

3.2 越权访问控制(Broken Access Control)

场景:用户 A 尝试访问 /api/users/123/profile(123 是用户 B)

错误实现

复制代码
@app.route('/api/users/<int:user_id>/profile')
@jwt_required()
def get_profile(user_id):
    # 直接返回,未校验当前用户是否为 owner
    return User.query.get(user_id).to_dict()

安全实现

复制代码
@app.route('/api/users/<int:user_id>/profile')
@jwt_required()
def get_profile(user_id):
    current_user_id = get_jwt_identity()
    
    # 关键:校验资源归属
    if current_user_id != user_id:
        # 或检查是否为管理员
        if not current_user.is_admin:
            abort(403, "Forbidden")
    
    return User.query.get(user_id).to_dict()

进阶 :使用 对象级权限库 (如 Flask-Principal)。

3.3 CSRF 防护(针对传统表单)

注意:纯 API + JWT 通常无需 CSRF(因无 Cookie 自动携带),但若使用 Session 则需防护。

启用 Flask-WTF:

复制代码
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)

前端发送 Token:

复制代码
// 从 meta 标签获取
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
axios.defaults.headers.common['X-CSRFToken'] = csrfToken;

3.4 速率限制(防暴力破解)

安装 flask-limiter

复制代码
pip install flask-limiter

配置:

复制代码
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

@app.route("/auth/login", methods=["POST"])
@limiter.limit("5 per minute")  # 登录接口严格限制
def login():
    # ...

策略

  • 登录:5 次/分钟
  • API:100 次/小时/IP
  • 管理员接口:更严格

第四章:API 与认证安全

4.1 JWT 安全最佳实践

风险 防御措施
Token 泄露 短有效期(access_token=15min)+ refresh_token 安全存储
重放攻击 使用 jti(JWT ID) + 黑名单(Redis 存储已注销 token)
算法混淆 强制指定算法(如 HS256),拒绝 alg: none

Token 注销示例

复制代码
@app.route('/auth/logout', methods=['POST'])
@jwt_required()
def logout():
    jti = get_jwt()['jti']
    # 加入黑名单,有效期 = 原 token 剩余时间
    redis.setex(f"blacklist:{jti}", expires_in, "true")
    return {"msg": "Logged out"}

验证时检查黑名单

复制代码
@jwt.token_in_blocklist_loader
def check_if_token_revoked(jwt_header, jwt_payload):
    jti = jwt_payload["jti"]
    return redis.exists(f"blacklist:{jti}")

4.2 敏感数据脱敏

响应中隐藏密码、身份证等:

复制代码
class UserSchema(Schema):
    id = fields.Int()
    username = fields.Str()
    email = fields.Email()
    # 不输出 password_hash
    # 身份证部分打码
    id_card = fields.Method("mask_id_card")

    def mask_id_card(self, obj):
        if obj.id_card:
            return obj.id_card[:6] + "****" + obj.id_card[-4:]
        return None

原则永远不要在日志、响应、前端存储中明文出现敏感字段。


第五章:安全配置与依赖管理

5.1 安全 HTTP 头

使用 flask-talisman 自动设置:

复制代码
from flask_talisman import Talisman

Talisman(app,
    force_https=True,
    strict_transport_security=True,
    content_security_policy=csp_policy,  # 同前端 CSP
    referrer_policy="strict-origin-when-cross-origin",
    x_frame_options="DENY"
)

5.2 依赖漏洞扫描

Python

复制代码
pip install safety
safety check -r requirements.txt

Node.js

复制代码
npm audit --audit-level high

CI 集成(GitHub Actions):

复制代码
- name: Check Python dependencies
  run: |
    pip install safety
    safety check -r requirements.txt --exit-code

策略:CI 中发现高危漏洞则失败。


第六章:自动化安全测试

6.1 静态代码分析

Python(Bandit)

复制代码
pip install bandit
bandit -r ./app -f json -o bandit-report.json

常见检测项:

  • 硬编码密码
  • 不安全的 pickle 使用
  • 未验证的重定向

前端(ESLint 安全插件)

复制代码
npm install -D eslint-plugin-security

.eslintrc.js

复制代码
plugins: ['security'],
rules: {
  'security/detect-object-injection': 'error',
  'security/detect-non-literal-fs-filename': 'error'
}

6.2 动态扫描:OWASP ZAP

启动 ZAP 扫描

复制代码
docker run -t owasp/zap2docker-stable zap-baseline.py \
  -t https://your-staging-domain.com \
  -r zap-report.html

CI 集成

复制代码
- name: Run ZAP Baseline Scan
  run: |
    docker run --network host -v $(pwd):/zap/wrk:z \
      owasp/zap2docker-stable zap-baseline.py \
      -t http://localhost:5000 \
      -x zap-report.xml

注意:ZAP 可能触发大量请求,仅用于测试环境。


第七章:渗透测试实战(手动验证)

7.1 测试越权(IDOR)

  1. 用用户 A 登录,获取其 user_id=100
  2. 修改请求为 GET /api/users/101/profile
  3. 预期:返回 403,而非用户 101 的数据

7.2 测试 XSS

  1. 在用户昵称输入 <script>alert(1)</script>
  2. 保存后刷新页面
  3. 预期:脚本不执行,仅显示文本

7.3 测试 SSRF(服务器端请求伪造)

若应用支持 webhook 或图片抓取:

复制代码
POST /api/fetch-image
{ "url": "http://169.254.169.254/latest/meta-data" }  # AWS 元数据

预期:返回错误,禁止访问内网 IP。

防御代码

复制代码
from urllib.parse import urlparse
import ipaddress

def is_safe_url(url):
    try:
        result = urlparse(url)
        # 检查是否为内网 IP
        addr = ipaddress.ip_address(socket.gethostbyname(result.hostname))
        return not addr.is_private and not addr.is_loopback
    except:
        return False

第八章:CI/CD 安全门禁

8.1 GitHub Actions 安全工作流

复制代码
name: Security Scan

on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Python
        uses: actions/setup-python@v4
        with: { python-version: '3.11' }
      
      - name: Install deps
        run: pip install -r requirements.txt -r requirements-dev.txt
      
      - name: Bandit Scan
        run: bandit -r ./app --exit-zero -f json | tee bandit.json
        
      - name: Safety Check
        run: safety check -r requirements.txt --exit-code
        
      - name: ESLint Security
        run: npm run lint:security
        
      - name: Fail on High Risk
        run: |
          if grep -q '"severity": "HIGH"' bandit.json; then
            echo "High risk found!"; exit 1
          fi

效果:PR 中若含高危漏洞,无法合并。


第九章:安全开发流程(SDL)

将安全融入开发全周期:

阶段 活动
需求 威胁建模(STRIDE)
设计 安全架构评审
编码 安全编码规范 + SAST
测试 DAST + 渗透测试
发布 依赖扫描 + 配置审计
运维 日志监控 + 应急响应

工具链

  • 威胁建模:Microsoft Threat Modeling Tool
  • SAST:Bandit, Semgrep
  • DAST:OWASP ZAP, Burp Suite

总结:构建纵深防御体系

相关推荐
唐叔在学习2 小时前
还在申请云服务器来传输数据嘛?试试P2P直连吧
后端·python
黄宝康2 小时前
sublimetext 运行python程序
开发语言·python
over6972 小时前
🌟 JavaScript 数组终极指南:从零基础到工程级实战
前端·javascript·前端框架
社恐的下水道蟑螂2 小时前
深入掌握 AI 全栈项目中的路由功能:从基础到进阶的全面解析
前端·react.js·全栈
米诺zuo2 小时前
Angular 18 核心特性速查表
前端
hey_ner2 小时前
进度条图表简单化
前端·css·css3
苏西的网络日志2 小时前
前端项目缓存控制与自动版本检查方案实现
前端
小遁哥2 小时前
通过AI从零开发RN到在安卓手机上运行
前端·react native·cursor
sure2822 小时前
react native中实现视频转歌
前端·react native