Відповідь нижче стосується в основному підписаних файлів cookie - реалізації концепції сеансів (як це використовується у веб-додатках). Flask пропонує як звичайні (непідписані) файли cookie (через request.cookies
та response.set_cookie()
), так і підписані файли cookie (через flask.session
). Відповідь складається з двох частин, перша описує, як створюється підписане печиво, а друга подається у формі якості, яка стосується різних аспектів схеми. Синтаксис, який використовується для прикладів, є Python3, але поняття стосуються також і попередніх версій.
Що таке SECRET_KEY
(чи як створити підписаний файл cookie)?
Підписання файлів cookie є запобіжним заходом проти фальсифікації файлів cookie. Під час підписання файлу cookie SECRET_KEY
використовується так, як "сіль" буде використовуватися для заблуднення пароля перед його хешированием. Ось (дико) спрощений опис концепції. Код у прикладах повинен бути ілюстративним. Багато етапів було опущено, і не всі функції існують насправді. Мета тут - дати розуміння загальної ідеї, реальні реалізації будуть задіяні трохи більше. Також майте на увазі, що Flask робить для вас більшу частину цього у фоновому режимі. Отже, окрім встановлення значень для файлу cookie (за допомогою API сеансу) та надання файлу SECRET_KEY
, не лише радимо повторно виконувати це, але й робити це не потрібно:
Підпис печива бідного чоловіка
Перш ніж надсилати відповідь веб-переглядачу:
(1) Спочатку a SECRET_KEY
встановлюється. Він повинен бути відомий лише програмі та повинен підтримуватися відносно постійним протягом життєвого циклу програми, в тому числі шляхом перезавантаження програми.
# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')
(2) створити печиво
>>> cookie = make_cookie(
... name='_profile',
... content='uid=382|membership=regular',
... ...
... expires='July 1 2030...'
... )
>>> print(cookie)
name: _profile
content: uid=382|membership=regular...
...
...
expires: July 1 2030, 1:20:40 AM UTC
(3) створити підпис, додати (або додати) SECRET_KEY
рядок байтів файлів cookie, а потім створити хеш із цієї комбінації.
# encode and salt the cookie, then hash the result
>>> cookie_bytes = str(cookie).encode('utf8')
>>> signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
>>> print(signature)
7ae0e9e033b5fa53aa....
(4) Тепер покладіть підпис на одному кінці content
поля оригінального файлу cookie.
# include signature as part of the cookie
>>> cookie.content = cookie.content + '|' + signature
>>> print(cookie)
name: _profile
content: uid=382|membership=regular|7ae0e9... <--- signature
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
і ось що надсилається клієнту.
# add cookie to response
>>> response.set_cookie(cookie)
# send to browser -->
Після отримання файлу cookie від браузера:
(5) Коли браузер поверне цей файл cookie назад на сервер, зніміть підпис з поля cookie, content
щоб повернути початковий файл cookie.
# Upon receiving the cookie from browser
>>> cookie = request.get_cookie()
# pop the signature out of the cookie
>>> (cookie.content, popped_signature) = cookie.content.rsplit('|', 1)
(6) Використовуйте оригінальне cookie з програмою SECRET_KEY
для перерахунку підпису, використовуючи той самий метод, що і на кроці 3.
# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
(7) Порівняйте обчислений результат із підписом, який раніше вийшов із щойно отриманого файлу cookie. Якщо вони відповідають, ми знаємо, що файл cookie не був заблокований. Але якщо до файлу cookie було додано навіть просто пробіл, підписи не збігаються.
# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature
(8) Якщо вони не відповідають, ви можете відповісти будь-якою кількістю дій, зареєструвати подію, відмовитись від файлів cookie, видати свіжий, перенаправити на сторінку входу тощо.
>>> if not good_cookie:
... security_log(cookie)
Код автентифікації повідомлень на основі хеша (HMAC)
Тип генерованого вище підпису, для якого потрібен секретний ключ, щоб забезпечити цілісність деякого вмісту, в криптографії називається кодом автентифікації повідомлення або MAC .
Раніше я зазначив, що приклад, наведений вище, - це надмірне спрощення цієї концепції і що не дуже вдало реалізувати власне підписання. Це тому, що алгоритм, який використовується для підписання файлів cookie у Flask, називається HMAC і є дещо більш задіяним, ніж описаний вище простий крок за кроком. Загальна ідея така ж, але через причини, що виходять за рамки цієї дискусії, ряд обчислень є набагато складнішим. Якщо ви все ще зацікавлені в тому, щоб створити саморобку, як це зазвичай буває, у Python є кілька модулів, які допоможуть вам почати роботу :) ось стартовий блок:
import hmac
import hashlib
def create_signature(secret_key, msg, digestmod=None):
if digestmod is None:
digestmod = hashlib.sha1
mac = hmac.new(secret_key, msg=msg, digestmod=digestmod)
return mac.digest()
Документальний документ для hmac та хешлібу .
"Демістифікація" SECRET_KEY
:)
Що таке "підпис" у цьому контексті?
Це спосіб гарантувати, що деякий вміст не було змінено іншим, окрім особи або суб'єкта, уповноваженого на це.
Однією з найпростіших форм підпису є " контрольна сума ", яка просто перевіряє, що два фрагменти даних однакові. Наприклад, при встановленні програмного забезпечення з джерела важливо спочатку підтвердити, що ваша копія вихідного коду ідентична авторській. Загальний підхід для цього - запустити джерело через функцію криптографічного хешу та порівняти вихідний з контрольною сумою, опублікованою на головній сторінці проекту.
Скажімо, наприклад, що ви збираєтесь завантажити джерело проекту у gzipped файл із веб-дзеркала. Контрольна сума SHA1, опублікована на веб-сторінці проекту, є "eb84e8da7ca23e9f83 ...."
# so you get the code from the mirror
download https://mirror.example-codedump.com/source_code.tar.gz
# you calculate the hash as instructed
sha1(source_code.tar.gz)
> eb84e8da7c....
Обидва хеші однакові, ви знаєте, що у вас є ідентична копія.
Що таке печиво?
Широка дискусія щодо файлів cookie вийде за межі цього питання. Я надаю огляд тут, оскільки мінімальне розуміння може бути корисним, щоб краще зрозуміти, як і навіщо SECRET_KEY
корисно. Я настійно рекомендую вам ознайомитися з деякими особистими читаннями на HTTP Cookies.
Поширена практика у веб-додатках - використовувати клієнт (веб-браузер) як легкий кеш. Файли cookie - це одна реалізація цієї практики. Файл cookie - це зазвичай деякі дані, які сервер додає у відповідь HTTP за допомогою заголовків. Він зберігається у браузері, який згодом надсилає його назад на сервер при видачі запитів, також через заголовки HTTP. Дані, що містяться в файлі cookie, можуть бути використані для імітації того, що називається нюховістю, ілюзія, що сервер підтримує постійний зв’язок з клієнтом. Тільки в цьому випадку замість дроту, щоб зберегти з'єднання "живим", у вас є просто знімки стану програми після того, як він обробив запит клієнта. Ці знімки передаються вперед і назад між клієнтом і сервером. Отримавши запит, сервер спочатку зчитує вміст файлу cookie, щоб відновити контекст його розмови з клієнтом. Потім він обробляє запит у цьому контексті і перед поверненням відповіді клієнту оновлює файл cookie. Таким чином зберігається ілюзія триваючої сесії.
Як виглядає печиво?
Типовий файл cookie виглядатиме так:
name: _profile
content: uid=382|status=genie
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
Файли cookie банально використовувати для будь-якого сучасного веб-переглядача. Наприклад, у Firefox перейдіть до Налаштування> Конфіденційність> Історія> видаліть окремі файли cookie .
content
Поле є найбільш значущим для застосування. Інші поля містять в основному мета інструкції, щоб вказати різні сфери впливу.
Навіщо взагалі використовувати файли cookie?
Коротка відповідь - це продуктивність. Використання файлів cookie мінімізує необхідність пошуку речей у різних сховищах даних (кеш пам'яті, файлів, баз даних тощо), тим самим прискорюючи роботи на стороні серверної програми. Майте на увазі, що чим більший розмір файлу cookie, тим важче корисне навантаження по мережі, тому те, що ви зберігаєте при пошуку бази даних на сервері, ви можете втратити через мережу. Подумайте уважно, що потрібно включити у файли cookie.
Чому печиво потрібно підписувати?
Файли cookie використовуються для зберігання всілякої інформації, частина якої може бути дуже чутливою. Вони також за своєю природою не є безпечними і вимагають вжити ряд допоміжних запобіжних заходів, щоб будь-яким чином вважатись безпечним для обох сторін, клієнта та сервера. Підписання файлів cookie вирішує проблему, з якою їх можна вирішити, намагаючись обдурити серверні програми. Існують і інші заходи щодо зменшення вразливості інших типів, я закликаю вас прочитати більше про файли cookie.
Як можна підробити печиво?
Файли cookie знаходяться на клієнті в текстовій формі і їх можна редагувати без особливих зусиль. Файли cookie, отримані вашою серверною програмою, могли бути змінені з кількох причин, деякі з яких можуть бути невинними. Уявіть веб-додаток, який зберігає інформацію про дозвіл своїх користувачів на файлах cookie та надає пільги на основі цієї інформації. Якщо файл cookie не є захищеним від посилань, кожен може змінити свій статус, щоб підвищити його статус з "role = відвідувач" на "role = admin", і програма не була б мудрішою.
Чому SECRET_KEY
потрібно підписувати файли cookie?
Перевірка файлів cookie є дещо іншою, ніж перевірка вихідного коду так, як це описано раніше. Що стосується вихідного коду, то оригінальним автором є довірена особа та власник опорного відбитка пальця (контрольної суми), який буде публічним. Те, що ви не довіряєте, - це вихідний код, але ви довіряєте публічному підпису. Отже, щоб підтвердити свою копію джерела, ви просто хочете, щоб ваш обчислений хеш відповідав загальнодоступному хешу.
Що стосується файлу cookie, програма не відслідковує підпис, вона відслідковує її SECRET_KEY
. Це SECRET_KEY
опорний відбиток. Файли cookie розміщуються з підписом, який вони вважають законним. Легітимність тут означає, що підпис видав власник файлу cookie, тобто додаток, і в цьому випадку це те ствердження, що ви не довіряєте, і вам потрібно перевірити підпис на дійсність. Для цього вам потрібно включити елемент у підпис, який вам відомий, саме це SECRET_KEY
. Хтось може змінити печиво, але оскільки у них немає секретного інгредієнта, щоб правильно обчислити дійсний підпис, він не може підробити його. Як було сказано трохи раніше, цей тип відбитків пальців, де поверх контрольної суми, також є секретний ключ,
Що з сесіями?
Сесії в їх класичній реалізації - це файли cookie, що містять у content
полі лише ідентифікатор , the session_id
. Мета сеансів точно така ж, як і підписані файли cookie, тобто запобігання підробці файлів cookie. Однак класичні заняття мають інший підхід. Після отримання файлу cookie сеансу сервер використовує ідентифікатор для пошуку даних сеансу у власній локальній пам’яті, яка може бути базою даних, файлом або іноді кешем пам’яті. Зазвичай сеансовий файл cookie встановлюється, коли браузер закриється. Через крок пошуку локальної пам’яті, ця реалізація сеансів зазвичай спричиняє показник ефективності. Підписані файли cookie стають бажаною альтернативою, і саме так реалізуються сесії Flask. Іншими слова, колби сесія єпідписані файли cookie, а щоб використовувати підписані файли cookie у Flask, просто використовуйте його Session
API.
Чому б також не зашифрувати файли cookie?
Іноді вміст файлів cookie можна зашифрувати до того, як вони також будуть підписані . Це робиться, якщо вони вважаються занадто чутливими, щоб бути видимими у браузері (шифрування приховує вміст). Однак, просто підписуючи файли cookie, вирішується інша потреба, яка потребує збереження певної видимості та зручності використання файлів cookie у веб-переглядачі, не допускаючи того, щоб вони могли бути порушені.
Що станеться, якщо я поміняю SECRET_KEY
?
Змінивши SECRET_KEY
ви недійсні всі файли cookie, підписані попереднім ключем. Коли програма отримає запит із файлом cookie, який був підписаний з попереднім SECRET_KEY
, він спробує обчислити підпис з новим SECRET_KEY
, і обидва підписи не збігаються, цей файл cookie та всі його дані будуть відхилені, це буде як би браузер підключається до сервера вперше. Користувачі вийдуть із системи, і їх старий файл cookie буде забутий, а також все, що зберігається всередині. Зауважте, що це відрізняється від способу обробки cookie з минулим терміном. Термін дії файлу cookie з минулим терміном може продовжити, якщо його підпис перевіряється. Недійсний підпис просто передбачає звичайний недійсний файл cookie.
Тому, якщо ви не хочете визнати недійсними всі підписані файли cookie, намагайтеся зберегти SECRET_KEY
те саме протягом тривалого періоду.
Що добре SECRET_KEY
?
Таємний ключ повинен бути важко здогадатися. Документація про сеанси має хороший рецепт генерації випадкових ключів:
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
Ви копіюєте ключ і вставляєте його у файл конфігурації як значення SECRET_KEY
.
Окрім використання ключа, який був генерований випадковим чином, ви могли використовувати складний асортимент слів, цифр та символів, можливо, розташованих у відомому вам реченні, закодованому у байтовій формі.
Ви НЕ встановити SECRET_KEY
безпосередньо з функцією , яка генерує інший ключ кожен раз , коли він називається. Наприклад, не робіть цього:
# this is not good
SECRET_KEY = random_key_generator()
Кожен раз, коли ваша програма перезапускається, їй буде наданий новий ключ, таким чином недійсний попередній.
Замість цього відкрийте інтерактивну оболонку пітона та зателефонуйте до функції, щоб створити ключ, а потім скопіюйте та вставте його у конфігурацію.