Подтвердить что ты не робот

Demystify Flask app.secret_key

Если app.secret_key не установлен, Flask не позволит вам установить или получить доступ к словарю сеансов.

Это все, что может сказать по этому поводу руководство пользователя колбы.

Я очень новичок в веб-разработке, и я понятия не имею, как/почему работает какой-либо элемент безопасности. Я хотел бы понять, что делает Flask под капотом.

  • Почему Flask заставляет нас устанавливать это свойство secret_key?
  • Как Flask использует свойство secret_key?
4b9b3361

Ответ 1

Все, что требует шифрования (для защиты от взлома злоумышленниками), требует установки секретного ключа. Для самого Flask это "что-нибудь" является объектом Session, но другие расширения могут использовать тот же секрет.

secret_key - это просто значение, установленное для SECRET_KEY конфигурации SECRET_KEY, или вы можете установить его напрямую.

В разделе " Сессии" в "Быстром старте" содержатся полезные советы о том, какой секрет на стороне сервера следует установить.

Шифрование опирается на секреты; если вы не установите секрет на стороне сервера для шифрования, каждый сможет взломать ваше шифрование; это как пароль к вашему компьютеру. Секрет плюс данные для подписи используются для создания строки подписи, трудно воссоздаемого значения с использованием криптографического алгоритма хеширования; только если у вас точно такой же секрет и исходные данные, вы можете воссоздать это значение, позволяя Flask обнаруживать, было ли что-либо изменено без разрешения. Поскольку секрет никогда не включается в данные, которые Flask отправляет клиенту, клиент не может вмешиваться в данные сеанса и надеется создать новую действительную подпись.

Flask использует свою itsdangerous библиотеку для выполнения всей тяжелой работы; сеансы используют класс itsdangerous.URLSafeTimedSerializer с настроенным сериализатором JSON.

Ответ 2

Ответ ниже относится главным образом к Signed Cookies, реализации концепции сессий (используемой в веб-приложениях). Flask предлагает как обычные (без знака) куки файлы (через request.cookies и response.set_cookie()), так и подписанные куки файлы (через flask.session). Ответ состоит из двух частей: первая описывает, как генерируется подписанный файл cookie, а вторая представлена в форме QA, которая затрагивает различные аспекты схемы. Синтаксис, используемый в примерах, - это Python3, но концепции применимы и к предыдущим версиям.

Что такое SECRET_KEY (или как создать подписанный SECRET_KEY)?

Подписание файлов cookie является профилактической мерой против подделки файлов cookie. Во время процесса подписания cookie файла SECRET_KEY используется аналогично тому, как "соль" используется для запутывания пароля перед его хешированием. Здесь (дико) упрощенное описание концепции. Код в примерах предназначен для иллюстрации. Многие из шагов были пропущены, и не все функции фактически существуют. Цель здесь - дать понимание общей идеи, фактические реализации будут немного более сложными. Кроме того, имейте в виду, что Flask делает большую часть этого для вас в фоновом режиме. Таким образом, помимо установки значений в ваш файл cookie (через сеансовый API) и предоставления SECRET_KEY, не только SECRET_KEY переопределять это самостоятельно, но в этом нет необходимости:

Подпись печенья бедного человека

Перед отправкой ответа в браузер:

(1) Сначала устанавливается 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 --> 

После получения куки из браузера:

(5) Когда браузер возвращает этот файл cookie обратно на сервер, удалите подпись из поля content файла cookie, чтобы получить исходный файл 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 добавлено только место, подписи не будут совпадать.

# 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 и немного более сложен, чем описанный выше шаг за шагом. Общая идея та же самая, но по причинам, выходящим за рамки этого обсуждения, ряд вычислений немного сложнее. Если вы все еще заинтересованы в создании DIY, как это обычно бывает, в 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 и hashlib.


"Демистификация" SECRET_KEY :)

Что за "подпись" в этом контексте?

Это способ гарантировать, что какой-либо контент не был изменен кем-либо, кроме лица или организации, уполномоченной на это.

Одна из самых простых форм подписи - это " контрольная сумма ", которая просто подтверждает, что два фрагмента данных совпадают. Например, при установке программного обеспечения из исходного кода важно сначала подтвердить, что ваша копия исходного кода идентична авторской. Обычный подход для этого - запустить исходный код с помощью криптографической хеш-функции и сравнить выходные данные с контрольной суммой, опубликованной на домашней странице проекта.

Допустим, например, что вы собираетесь загрузить исходный код проекта в сжатом файле из веб-зеркала. Контрольная сумма 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 полезен. Я настоятельно рекомендую вам ознакомиться с некоторыми личными статьями о файлах cookie HTTP.

Обычной практикой в веб-приложениях является использование клиента (веб-браузера) в качестве облегченного кэша. Файлы cookie являются одной из реализаций этой практики. Cookie - это, как правило, некоторые данные, добавляемые сервером в ответ HTTP посредством его заголовков. Он сохраняется браузером, который впоследствии отправляет его обратно на сервер при выдаче запросов, в том числе посредством заголовков HTTP. Данные, содержащиеся в 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 файлы не защищены от несанкционированного доступа, любой может изменить их, чтобы повысить свой статус с "role = visitor" до "role = admin", и приложение не будет мудрым.

Почему SECRET_KEY необходимо подписывать куки?

Проверка файлов cookie немного отличается от проверки исходного кода, как это было описано ранее. В случае исходного кода первоначальный автор является доверенным лицом и владельцем эталонного отпечатка пальца (контрольной суммы), который будет храниться в открытом доступе. Вы не доверяете исходному коду, но доверяете публичной подписи. Таким образом, чтобы проверить свою копию источника, вы просто хотите, чтобы ваш вычисленный хеш соответствовал общедоступному хешу.

Однако в случае файла cookie приложение не отслеживает подпись, оно отслеживает его SECRET_KEY. SECRET_KEY - это эталонный отпечаток. Куки файлы путешествуют с подписью, которую они считают законной. Легитимность здесь означает, что подпись была выдана владельцем куки файла, то есть приложения, и в этом случае это утверждение, что вы не доверяете, и вам необходимо проверить подпись на достоверность. Для этого вам нужно включить в подпись только известный вам SECRET_KEY - SECRET_KEY. Кто-то может изменить cookie файл, но, поскольку у него нет секретного компонента для правильного вычисления действительной подписи, он не может подделать его. Как указывалось ранее, этот тип дактилоскопии, где помимо контрольной суммы также предоставляется секретный ключ, называется кодом аутентификации сообщения.

Как насчет сессий?

Сеансы в их классической реализации представляют собой файлы cookie, которые содержат только идентификатор в поле content session_id. Назначение сеансов точно такое же, как и для подписанных файлов cookie, т.е. для предотвращения подделки файлов cookie. Классические сессии имеют другой подход, хотя. После получения файла cookie сеанса сервер использует идентификатор для поиска данных сеанса в своем собственном локальном хранилище, которое может быть базой данных, файлом или иногда кэшем в памяти. Сеансовый cookie файл обычно устанавливается на срок действия при закрытии браузера. Из-за шага поиска в локальном хранилище такая реализация сеансов обычно вызывает снижение производительности. Подписанные cookie файлы становятся предпочтительной альтернативой, и таким образом реализуются сеансы Flask. Другими словами, сеансы Flask являются подписанными cookie файлами, а чтобы использовать подписанные cookie файлы в Flask, просто используйте его Session API.

Почему бы не зашифровать куки?

Иногда содержимое файлов cookie может быть зашифровано перед тем, как подписано. Это делается, если они считаются слишком чувствительными, чтобы быть видимыми из браузера (шифрование скрывает содержимое). Однако простая подпись cookie файлов решает другую проблему, когда требуется сохранить наглядность и удобство использования cookie файлов в браузере, не допуская, чтобы на них вмешивались.

Что произойдет, если я изменю SECRET_KEY?

Изменяя SECRET_KEY вы SECRET_KEY законной силы все куки, подписанные предыдущим ключом. Когда приложение получает запрос с файлом 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()

Каждый раз, когда ваше приложение перезапускается, ему дается новый ключ, что делает предыдущий недействительным.

Вместо этого откройте интерактивную оболочку python и вызовите функцию для генерации ключа, затем скопируйте и вставьте его в конфигурацию.