microdot.csrf --- CSRF 防护

拒绝源自跨站点的状态变更请求。该检查作为 before_request 钩子运行,并使用浏览器提供的 Sec-Fetch-Site 标头(在与 microdot.cors.CORS 实例配合使用时,对较旧的浏览器以 Origin 标头作为回退)。

class CSRF

class microdot.csrf.CSRF(app: Microdot | None = None, cors=None, protect_all: bool = True, allow_subdomains: bool = False)
app

要安装到的 microdot.Microdot 实例。可选;如果未给出,可稍后调用 initialize()

cors

定义应用程序受信任源的 microdot.cors.CORS 实例。对于在不发送 Sec-Fetch-Site 的浏览器上回退到 Origin 标头而言是必需的。可选;不提供时,仅应用 Sec-Fetch-Site 检查。

protect_all

如果为 True(默认),则除 GETHEADOPTIONS 之外的每个路由都会被自动保护。可以用 exempt() 单独豁免路由。如果为 False,则默认不保护任何路由,由各个路由用 protect() 选择性加入。

allow_subdomains

如果为 True,则接受来自应用程序源的子域的请求(same-site 的 Sec-Fetch-Site,或匹配的源后缀)。

initialize(app: Microdot, cors=None)

如果构造时延迟了附加,则附加到 app

exempt(f)

使路由免于 CSRF 防护的装饰器。将其直接置于路由装饰器之后:

@app.post('/webhook')
@csrf.exempt
async def webhook(request):
    # accepts cross-site POSTs
protect(f)

对原本会被豁免的路由(例如 GET 路由,或 protect_all=False 时的每个路由)强制启用 CSRF 防护的装饰器。

SAFE_METHODS: list

列出默认不受保护的方法的类属性——['GET', 'HEAD', 'OPTIONS']

示例:

from microdot import Microdot
from microdot.cors import CORS
from microdot.csrf import CSRF

app = Microdot()
cors = CORS(app, allowed_origins=['https://app.example.com'])
csrf = CSRF(app, cors=cors)

@app.post('/api/save')
async def save(request):
    # automatically CSRF-protected
    return {'ok': True}

Sec-Fetch-Site 报告 same-originnone(或在 allow_subdomains=True 时报告 same-site)时,请求被允许。如果该标头不存在,则将请求的 Origin 与 CORS 允许列表进行匹配。两个标头都没有的请求会被接受(对于不受浏览器 CSRF 约束的直接 API 调用而言是典型情况)。