Код-ревью Senior Аутентификация и сессии обновлено

Ревью: callback OAuth на Python

Вопрос

Найдите проблемы в обработчике входа через внешнего провайдера (OIDC).

@app.get("/oauth/callback")
def callback():
    code = request.args["code"]
    tokens = requests.post(TOKEN_URL, data={
        "grant_type": "authorization_code", "code": code,
        "redirect_uri": request.args.get("redirect_uri", DEFAULT_REDIRECT),
        "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET,
    }).json()
    claims = jwt.decode(tokens["id_token"], options={"verify_signature": False})
    user = find_or_create(email=claims["email"])
    session["user_id"] = user.id
    return redirect(request.args.get("next", "/"))

Коротко

OIDC безопасен, только если выполнены все проверки протокола. Связывать аккаунты лучше по паре (issuer, sub), а email использовать только подтверждённый.

Что должен найти ревьюер

  1. Безопасностьстрока 3
    Не проверяется параметр state: CSRF на callback, атакующий может залогинить жертву в свой аккаунт.
  2. Безопасностьстрока 6
    redirect_uri берётся из запроса, а должен быть фиксированным и совпадать с зарегистрированным.
  3. Безопасностьстрока 9
    Подпись ID-токена не проверяется, а также iss, aud, exp, nonce: токен можно подделать.
  4. Безопасностьстрока 10
    Пользователь ищется по email без проверки email_verified и без привязки к sub провайдера: захват аккаунта через неподтверждённый email.
  5. Безопасностьстрока 11
    Сессия не перевыпускается при входе.
  6. Безопасностьстрока 12
    Открытый редирект через next.
  7. Безопасностьстрока 4
    Нет PKCE (code_verifier) при обмене кода.

Разбор

OIDC безопасен, только если выполнены все проверки протокола. Связывать аккаунты лучше по паре (issuer, sub), а email использовать только подтверждённый.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.