安全响应头中间件:X-Content-Type-Options / X-Frame-Options / X-XSS-Protection

一句话:安全响应头是 HTTP 响应头,用于增强 Web 应用的安全性,防止常见攻击如点击劫持、MIME 类型嗅探、XSS 等。在 FastAPI 中,可以通过中间件添加这些响应头。

1. 常见安全响应头

1.1 响应头分类


graph TD

    A[安全响应头] --> B[内容安全]

    A --> C[传输安全]

    A --> D[访问控制]

    B --> B1[X-Content-Type-Options]

    B --> B2[X-XSS-Protection]

    B --> B3[Content-Security-Policy]

    C --> C1[Strict-Transport-Security]

    C --> C2[Content-Security-Policy]

    D --> D1[X-Frame-Options]

    D --> D2[Referrer-Policy]

    D --> D3[Permissions-Policy]

1.2 重要性

响应头防护攻击重要性
X-Content-Type-OptionsMIME 类型嗅探
X-Frame-Options点击劫持
X-XSS-ProtectionXSS 攻击
Strict-Transport-Security中间人攻击
Content-Security-PolicyXSS、数据注入

2. X-Content-Type-Options

2.1 作用

防止浏览器 MIME 类型嗅探,强制按照 Content-Type 响应头解析内容。

 
# 浏览器严格按照 Content-Type 解析
 

2.2 实现

 
from fastapi import FastAPI, Request, Response
 
app = FastAPI()
 
@app.middleware("http")
 
async def add_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # X-Content-Type-Options
 
    response.headers["X-Content-Type-Options"] = "nosniff"
 
    return response
 

3. X-Frame-Options

3.1 作用

防止网页被嵌入到 iframe 中,防止点击劫持攻击。

 
# X-Frame-Options 防止这种攻击
 

3.2 取值

说明
DENY完全禁止嵌入
SAMEORIGIN允许同源嵌入
ALLOW-FROM uri允许指定来源嵌入

3.3 实现

 
@app.middleware("http")
 
async def add_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # X-Frame-Options
 
    response.headers["X-Frame-Options"] = "DENY"
 
    # 或
 
    # response.headers["X-Frame-Options"] = "SAMEORIGIN"
 
    return response
 

4. X-XSS-Protection

4.1 作用

启用浏览器的 XSS 过滤器,防止反射型 XSS 攻击。

 
# 但为了兼容旧浏览器,仍建议添加
 

4.2 取值

说明
0禁用过滤器
1启用过滤器(默认)
1; mode=block启用过滤器,阻止页面渲染

4.3 实现

 
@app.middleware("http")
 
async def add_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # X-XSS-Protection
 
    response.headers["X-XSS-Protection"] = "1; mode=block"
 
    return response
 

5. Strict-Transport-Security (HSTS)

5.1 作用

强制浏览器使用 HTTPS,防止降级攻击。

 
# 3. 预加载列表(可选)
 

5.2 实现

 
@app.middleware("http")
 
async def add_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # Strict-Transport-Security
 
    response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
 
    return response
 

6. Content-Security-Policy (CSP)

6.1 作用

防止 XSS 和数据注入攻击,限制资源加载来源。

 
# 3. 禁止 eval()
 

6.2 常见指令

指令说明
default-src默认资源来源
script-src脚本来源
style-src样式来源
img-src图片来源
connect-srcAJAX/WebSocket 来源

6.3 实现

 
@app.middleware("http")
 
async def add_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # Content-Security-Policy
 
    csp = (
 
        "default-src 'self'; "
 
        "script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
 
        "style-src 'self' 'unsafe-inline'; "
 
        "img-src 'self' data: https:; "
 
        "font-src 'self' data:; "
 
        "connect-src 'self' https://api.example.com;"
 
    )
 
    response.headers["Content-Security-Policy"] = csp
 
    return response
 

7. 完整中间件实现

7.1 基础版本

 
from fastapi import FastAPI, Request
 
from starlette.middleware.base import BaseHTTPMiddleware
 
app = FastAPI()
 
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
 
    async def dispatch(self, request: Request, call_next):
 
        response = await call_next(request)
 
        # 安全响应头
 
        security_headers = {
 
            "X-Content-Type-Options": "nosniff",
 
            "X-Frame-Options": "DENY",
 
            "X-XSS-Protection": "1; mode=block",
 
            "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
 
            "Referrer-Policy": "strict-origin-when-cross-origin",
 
            "Permissions-Policy": "camera=(), microphone=(), geolocation=()",
 
        }
 
        for header, value in security_headers.items():
 
            response.headers[header] = value
 
        return response
 
app.add_middleware(SecurityHeadersMiddleware)
 

7.2 高级版本(可配置)

 
from fastapi import FastAPI, Request
 
from starlette.middleware.base import BaseHTTPMiddleware
 
from typing import Dict, Optional
 
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
 
    def __init__(
 
        self,
 
        app,
 
        headers: Optional[Dict[str, str]] = None,
 
        csp: Optional[str] = None,
 
    ):
 
        super().__init__(app)
 
        self.headers = headers or {
 
            "X-Content-Type-Options": "nosniff",
 
            "X-Frame-Options": "DENY",
 
            "X-XSS-Protection": "1; mode=block",
 
            "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
 
            "Referrer-Policy": "strict-origin-when-cross-origin",
 
        }
 
        self.csp = csp
 
    async def dispatch(self, request: Request, call_next):
 
        response = await call_next(request)
 
        # 添加默认安全头
 
        for header, value in self.headers.items():
 
            response.headers[header] = value
 
        # 添加CSP
 
        if self.csp:
 
            response.headers["Content-Security-Policy"] = self.csp
 
        return response
 
# 使用
 
app = FastAPI()
 
csp = (
 
    "default-src 'self'; "
 
    "script-src 'self' 'unsafe-inline'; "
 
    "style-src 'self' 'unsafe-inline'; "
 
)
 
app.add_middleware(
 
    SecurityHeadersMiddleware,
 
    csp=csp
 
)
 

8. AI应用中的安全头

8.1 API 安全头

 
@app.middleware("http")
 
async def add_api_security_headers(request: Request, call_next):
 
    response = await call_next(request)
 
    # API特定安全头
 
    response.headers["X-Content-Type-Options"] = "nosniff"
 
    response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate"
 
    response.headers["Pragma"] = "no-cache"
 
    # CORS相关
 
    response.headers["Access-Control-Allow-Origin"] = "*"
 
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
 
    response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
 
    return response
 

8.2 LLM API 安全头

 
@app.post("/api/llm/chat")
 
async def chat_with_llm(request: Request):
 
    response = await call_llm_api(request)
 
    # LLM响应安全头
 
    response.headers["X-Content-Type-Options"] = "nosniff"
 
    response.headers["Content-Security-Policy"] = "default-src 'none'"
 
    response.headers["Cache-Control"] = "no-store"
 
    return response
 

9. 常见坑点

1. 过度限制

 
# 问题:CSP太严格导致正常功能无法使用
 
csp = "default-src 'none'"  # 太严格
 
# 解决:根据实际需求调整
 
csp = "default-src 'self'; script-src 'self' 'unsafe-inline'"
 

2. 忘记测试

 
# 解决:在开发环境测试每个安全头的影响
 

3. 兼容性问题

 
# 解决:使用渐进增强策略
 
if request.headers.get("user-agent", "").startswith("Mozilla/5.0"):
 
    # 为旧浏览器添加兼容头
 
    response.headers["X-XSS-Protection"] = "1; mode=block"
 

核心要点

 
from fastapi import FastAPI, Request
 
from starlette.middleware.base import BaseHTTPMiddleware
 
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
 
    async def dispatch(self, request: Request, call_next):
 
        response = await call_next(request)
 
        response.headers["X-Content-Type-Options"] = "nosniff"
 
        response.headers["X-Frame-Options"] = "DENY"
 
        response.headers["X-XSS-Protection"] = "1; mode=block"
 
        response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
 
        response.headers["Content-Security-Policy"] = "default-src 'self'"
 
        return response
 
app = FastAPI()
 
app.add_middleware(SecurityHeadersMiddleware)
 

速记卡(面试闪卡)

Q1:一句话讲清「安全响应头中间件:X-Content-Type-Options / X-Frame-Options / X-XSS-Protection」到底是什么?

A:安全响应头是加在 HTTP 响应上的字段,用于防点击劫持、MIME 嗅探、XSS 等攻击,FastAPI 可用中间件统一添加。

Q2:1. 常见安全响应头 —— 怎么理解?

A:常见安全头分三类:内容安全(X-Content-Type-Options、X-XSS-Protection、CSP)、传输安全(HSTS)、访问控制(X-Frame-Options、Referrer-Policy、Permissions-Policy)。重要性:X-Content-Type-Options 防 MIME 嗅探(高)、X-Frame-Options 防点击劫持(高)、X-XSS-Protection 防 XSS(中)、Strict-Transport-Security 防中间人(高)。

Q3:2. X-Content-Type-Options —— 怎么理解?

A:X-Content-Type-Options: nosniff 强制浏览器按 Content-Type 解析,禁止 MIME 类型嗅探(英文 MIME Sniffing)——否则一张 image/png 可能被当可执行脚本跑。FastAPI 里在中间件 response.headers["X-Content-Type-Options"]="nosniff" 即可,几乎零成本却堵住一大类攻击。

Q4:3. X-Frame-Options —— 怎么理解?

A:X-Frame-Options 防网页被嵌进透明 iframe 搞点击劫持(英文 Clickjacking,你以为在点自己网站、实际在操作攻击者界面)。取值:DENY 完全禁止嵌入、SAMEORIGIN 允许同源、ALLOW-FROM uri 允许指定来源。现代项目更推荐用 CSP 的 frame-ancestors 替代。

Q5:6. Content-Security-Policy (CSP) —— 怎么理解?

A:CSP(Content-Security-Policy)防 XSS 和数据注入,限制资源加载来源:default-src、script-src、style-src、img-src、connect-src 等。场景:禁止内联脚本、禁止 eval、只允许自家域名资源。最严格 default-src 'none' 会误伤正常功能,要按实际需求放宽。可配置中间件统一下发。

Q6:核心速记主线有哪些?

  • 安全头分内容/传输/访问三类,中间件统一添加

  • X-Content-Type-Options: nosniff 防 MIME 嗅探

  • X-Frame-Options 防点击劫持(DENY/SAMEORIGIN)

  • CSP 控资源来源防 XSS;XSS-Protection 已弃用,用 CSP 替代

口诀

A:安全响应头中间件,三类防护一锅端;

nosniff 防嗅探,frame 防劫持嵌;

CSP 锁资源,XSS 无处钻;

HSTS 强制 HTTPS,中间人难偷看。

相关链接