fastapi/docs/uk/docs/advanced/security/http-basic-auth.md

108 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# HTTP Basic Auth { #http-basic-auth }
Для найпростіших випадків ви можете використовувати HTTP Basic Auth.
У HTTP Basic Auth застосунок очікує заголовок, що містить ім'я користувача та пароль.
Якщо він його не отримує, повертається помилка HTTP 401 «Unauthorized».
І повертається заголовок `WWW-Authenticate` зі значенням `Basic` та необов'язковим параметром `realm`.
Це каже браузеру показати вбудовану підсказку для введення імені користувача та пароля.
Потім, коли ви введете це ім'я користувача та пароль, браузер автоматично надішле їх у заголовку.
## Простий HTTP Basic Auth { #simple-http-basic-auth }
- Імпортуйте `HTTPBasic` і `HTTPBasicCredentials`.
- Створіть «`security` scheme» за допомогою `HTTPBasic`.
- Використайте цей `security` як залежність у вашій операції шляху.
- Він повертає об'єкт типу `HTTPBasicCredentials`:
- Він містить надіслані `username` і `password`.
{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
Коли ви спробуєте відкрити URL вперше (або натиснете кнопку «Execute» у документації), браузер попросить вас ввести ім'я користувача та пароль:
<img src="/img/tutorial/security/image12.png">
## Перевірте ім'я користувача { #check-the-username }
Ось більш повний приклад.
Використайте залежність, щоб перевірити, чи правильні ім'я користувача та пароль.
Для цього використайте стандартний модуль Python [`secrets`](https://docs.python.org/3/library/secrets.html), щоб перевірити ім'я користувача та пароль.
`secrets.compare_digest()` повинен отримувати `bytes` або `str`, що містить лише ASCII-символи (англійські), це означає, що він не працюватиме з символами на кшталт `á`, як у `Sebastián`.
Щоб це обійти, ми спочатку перетворюємо `username` і `password` у `bytes`, кодувавши їх у UTF-8.
Потім ми можемо використати `secrets.compare_digest()`, щоб упевнитися, що `credentials.username` дорівнює `"stanleyjobson"`, а `credentials.password` дорівнює `"swordfish"`.
{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
Це було б подібно до:
```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# Поверніть якусь помилку
...
```
Але використовуючи `secrets.compare_digest()`, це буде захищено від типу атак, що називаються «атаки за часом» (timing attacks).
### Атаки за часом { #timing-attacks }
Що таке «атака за часом»?
Уявімо, що зловмисники намагаються вгадати ім'я користувача та пароль.
Вони надсилають запит з ім'ям користувача `johndoe` та паролем `love123`.
Тоді Python-код у вашому застосунку буде еквівалентний чомусь на кшталт:
```Python
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...
```
Але в той момент, коли Python порівнює першу `j` у `johndoe` з першою `s` у `stanleyjobson`, він поверне `False`, тому що вже знає, що ці дві строки не однакові, «немає сенсу витрачати обчислення на порівняння решти літер». І ваш застосунок скаже «Невірні ім'я користувача або пароль».
А потім зловмисники спробують з ім'ям користувача `stanleyjobsox` і паролем `love123`.
І ваш код застосунку зробить щось на кшталт:
```Python
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...
```
Python доведеться порівняти весь `stanleyjobso` у обох `stanleyjobsox` і `stanleyjobson`, перш ніж зрозуміти, що строки різні. Тому відповідь «Невірні ім'я користувача або пароль» займе на кілька мікросекунд довше.
#### Час відповіді допомагає зловмисникам { #the-time-to-answer-helps-the-attackers }
У цей момент, помітивши, що сервер витратив на кілька мікросекунд більше, щоб надіслати відповідь «Невірні ім'я користувача або пароль», зловмисники знатимуть, що вони щось вгадали, деякі початкові літери правильні.
І тоді вони можуть спробувати знову, знаючи, що це, ймовірно, щось більш схоже на `stanleyjobsox`, ніж на `johndoe`.
#### «Професійна» атака { #a-professional-attack }
Звісно, зловмисники не робитимуть усе це вручну, вони напишуть програму, можливо з тисячами або мільйонами перевірок за секунду. І вони отримуватимуть лише по одній правильній літері за раз.
Але так за кілька хвилин або годин зловмисники вгадають правильні ім'я користувача та пароль, «за допомогою» нашого застосунку, просто використовуючи час, потрібний для відповіді.
#### Виправте за допомогою `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }
Але в нашому коді ми насправді використовуємо `secrets.compare_digest()`.
Коротко, він витрачає однаковий час на порівняння `stanleyjobsox` зі `stanleyjobson`, як і на порівняння `johndoe` зі `stanleyjobson`. І так само для пароля.
Таким чином, використовуючи `secrets.compare_digest()` у коді вашого застосунку, він буде захищений від усього цього класу атак безпеки.
### Поверніть помилку { #return-the-error }
Після виявлення, що облікові дані неправильні, поверніть `HTTPException` з кодом статусу 401 (такий самий повертається, коли облікові дані не надані) і додайте заголовок `WWW-Authenticate`, щоб браузер знову показав підсказку входу:
{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}