microdot.csrf — защита от CSRF

Отклоняет изменяющие состояние запросы, исходящие с другого сайта. Проверка выполняется как хук before_request и использует предоставляемый браузером заголовок Sec-Fetch-Site (с заголовком Origin в качестве запасного варианта для старых браузеров, в сочетании с экземпляром microdot.cors.CORS).

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, определяющий доверенные источники приложения. Требуется для перехода к заголовку Origin в браузерах, не отправляющих Sec-Fetch-Site. Необязательно; без него применяется только проверка Sec-Fetch-Site.

protect_all

Если True (по умолчанию), каждый маршрут, кроме GET, HEAD и OPTIONS, защищается автоматически. Маршруты можно исключать по отдельности с помощью 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)

Декоратор, который принудительно включает защиту CSRF для маршрута, который иначе был бы исключён (например, маршрут GET или каждый маршрут при protect_all=False).

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-origin или none (или same-site при allow_subdomains=True). Если заголовок отсутствует, заголовок Origin запроса сопоставляется со списком разрешённых источников CORS. Запросы без обоих заголовков принимаются (что характерно для прямых вызовов API, не подверженных браузерному CSRF).