web-dev-qa-db-fra.com

démystifier Flask app.secret_key

Si app.secret_key n'est pas défini, Flask ne vous permettra pas de définir ou d'accéder au dictionnaire de session.

C'est tout ce que le guide de l'utilisateur du flacon a à dire sur le sujet.

Je suis très novice dans le développement Web et je ne sais pas du tout comment et pourquoi aucun problème de sécurité ne fonctionne. Je voudrais comprendre ce que Flask fait sous le capot.

  • Pourquoi Flask nous oblige-t-il à définir ceci secret_key propriété?
  • Comment Flask utilise-t-il le secret_key propriété?
100
MYV

Tout ce qui nécessite un cryptage (pour se protéger des altérations par des attaquants) nécessite la définition de la clé secrète. Pour simplement Flask lui-même, cet objet est l'objet Session, mais d'autres extensions peuvent utiliser le même secret.

secret_key est simplement la valeur définie pour le SECRET_KEY clé de configuration, ou vous pouvez le définir directement.

La section section Sessions de Quickstart contient de bons conseils judicieux sur le type de secret côté serveur à définir.

Le cryptage repose sur des secrets; Si vous ne définissez pas de secret côté serveur pour le chiffrement, tout le monde pourrait briser votre chiffrement. c'est comme le mot de passe de votre ordinateur. Le secret plus les données à signer sont utilisés pour créer une chaîne de signature, une valeur difficile à recréer à l'aide d'un algorithme de hachage cryptographique ; pouvez uniquement recréer cette valeur si et les données d'origine vous permettent de recréer cette valeur, en laissant Flask détecter si a été modifié sans autorisation. Comme le secret n’est jamais inclus dans les données Flask est envoyé au client, un client ne peut pas falsifier les données de la session et espère produire une nouvelle signature valide.

Flask utilise la itsdangerous library pour faire tout le travail difficile; les sessions utilisent le itsdangerous.URLSafeTimedSerializer class avec un sérialiseur JSON personnalisé.

82
Martijn Pieters

La réponse ci-dessous concerne principalement les cookies signés , une implémentation du concept de sessions (tel qu'utilisé dans les applications Web). Flask propose à la fois des cookies normaux (non signés) (via request.cookies Et response.set_cookie()) et des cookies signés (via flask.session). La réponse se compose de deux parties, la première décrit la création d’un cookie signé et la seconde, sous la forme d’un contrôle qualité qui aborde différents aspects du schéma. La syntaxe utilisée dans les exemples est Python3, mais les concepts s’appliquent également aux versions précédentes. .

Qu'est-ce que SECRET_KEY (Ou comment créer un cookie signé)?

Signer des cookies est une mesure préventive contre la manipulation des cookies. Lors du processus de signature d'un cookie, le SECRET_KEY Est utilisé de la même manière qu'un "sel" serait utilisé pour confondre un mot de passe avant de le hacher. Voici une description (sauvagement) simplifiée du concept. Le code dans les exemples se veut illustratif. De nombreuses étapes ont été omises et toutes les fonctions n'existent pas réellement. L'objectif ici est de fournir une compréhension de l'idée générale, les implémentations réelles seront un peu plus impliquées. N'oubliez pas non plus que Flask s'occupe principalement de cela en arrière-plan. Donc, outre la définition de valeurs pour votre cookie (via l'API de session) et la fourniture d'un SECRET_KEY, il est non seulement mal avisé de réimplémenter cela vous-même, mais ce n'est pas la peine de le faire:

Signature du biscuit d'un homme pauvre

Avant d'envoyer une réponse au navigateur:

(1) Tout d'abord un SECRET_KEY Est établi. Elle ne doit être connue que de l'application et doit être maintenue relativement constante pendant le cycle de vie de l'application, y compris lors des redémarrages de l'application.

# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')

(2) créer un cookie

>>> 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) pour créer une signature, ajouter (ou ajouter) le SECRET_KEY À la chaîne d'octets du cookie, puis générer un hachage à partir de cette combinaison.

# 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) Maintenant, apposez la signature à une extrémité du champ content du cookie d'origine.

# 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

et c'est ce qui est envoyé au client.

# add cookie to response
>>> response.set_cookie(cookie)
# send to browser --> 

A la réception du cookie du navigateur:

(5) Lorsque le navigateur renvoie ce cookie au serveur, supprimez la signature du champ content du cookie pour récupérer le cookie d'origine.

# 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) Utilisez le cookie d'origine avec le SECRET_KEY De l'application pour recalculer la signature en utilisant la même méthode qu'à l'étape 3.

# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()

(7) Comparez le résultat calculé avec la signature précédemment extraite du cookie que vous venez de recevoir. S'ils correspondent, nous savons que le cookie n'a pas été gâché. Mais si même un espace a été ajouté au cookie, les signatures ne correspondront pas.

# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature

(8) S'ils ne correspondent pas, vous pouvez répondre avec un nombre quelconque d'actions, enregistrer l'événement, supprimer le cookie, en créer un nouveau, rediriger vers une page de connexion, etc.

>>> if not good_cookie:
...     security_log(cookie)

Code d'authentification de message basé sur le hachage (HMAC)

Le type de signature générée ci-dessus qui nécessite une clé secrète pour garantir l’intégrité de certains contenus est appelé dans la cryptographie un code d’authentification de message ou [~ # ~] mac [~ # ~] .

J'ai précisé précédemment que l'exemple ci-dessus est une simplification excessive de ce concept et qu'il n'était pas judicieux d'implémenter votre propre signature. C'est parce que l'algorithme utilisé pour enregistrer les cookies dans Flask est appelé HMAC et est un peu plus complexe que la simple étape ci-dessus. L'idée générale est la même, mais pour des raisons dépassant le cadre de cette discussion, la série de calculs est un peu plus complexe. Si vous souhaitez toujours créer un bricolage, comme c'est généralement le cas , Python a quelques modules pour vous aider à démarrer :) voici un bloc de départ:

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()

La documentation pour hmac et hashlib .


La "démystification" de SECRET_KEY :)

Qu'est-ce qu'une "signature" dans ce contexte?

C'est une méthode pour s'assurer que certains contenus n'ont pas été modifiés par une personne autre qu'une personne ou une entité autorisée à le faire.

Une des formes les plus simples de signature est le " checksum ", qui vérifie simplement que deux données sont identiques. Par exemple, lors de l’installation de logiciels à partir des sources, il est important de vérifier au préalable que votre copie du code source est identique à celle de l’auteur. Une approche courante consiste à exécuter le source à l'aide d'une fonction de hachage cryptographique et à comparer le résultat avec la somme de contrôle publiée sur la page d'accueil du projet.

Disons par exemple que vous êtes sur le point de télécharger la source d'un projet dans un fichier compressé à partir d'un miroir Web. La somme de contrôle SHA1 publiée sur la page Web du projet est "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....

Les deux hash sont les mêmes, vous savez que vous avez une copie identique.

C'est quoi un cookie?

Une discussion approfondie sur les cookies dépasserait le cadre de cette question. Je donne un aperçu ici car une compréhension minimale peut être utile pour mieux comprendre comment et pourquoi SECRET_KEY Est utile. Je vous encourage vivement à faire des lectures personnelles sur les cookies HTTP.

Une pratique courante dans les applications Web consiste à utiliser le client (navigateur Web) en tant que cache léger. Les cookies sont une mise en œuvre de cette pratique. Un cookie est généralement constitué de données ajoutées par le serveur à une réponse HTTP via ses en-têtes. Il est conservé par le navigateur qui le renvoie ensuite au serveur lors de l'envoi des requêtes, également via des en-têtes HTTP. Les données contenues dans un cookie peuvent être utilisées pour émuler ce que l’on appelle statefulness , l’illusion que le serveur maintient une connexion en cours avec le client. Seulement, dans ce cas, au lieu d’un fil permettant de garder la connexion "vivante", vous avez simplement des instantanés de l’état de l’application une fois que celle-ci a traité la demande du client. Ces instantanés sont échangés entre le client et le serveur. Lors de la réception d'une demande, le serveur lit d'abord le contenu du cookie pour rétablir le contexte de sa conversation avec le client. Il traite ensuite la demande dans ce contexte et, avant de renvoyer la réponse au client, met à jour le cookie. L'illusion d'une session en cours est donc maintenue.

A quoi ressemble un cookie?

Un cookie typique ressemblerait à ceci:

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

Les cookies sont faciles à lire depuis n'importe quel navigateur moderne. Sur Firefox par exemple, accédez à Préférences> Confidentialité> Historique> supprimer les cookies individuels .

Le champ content est le plus pertinent pour l'application. D'autres champs portent principalement des méta-instructions pour spécifier divers champs d'influence.

Pourquoi utiliser des cookies?

La réponse courte est la performance. L'utilisation de cookies minimise le besoin de rechercher des informations dans divers magasins de données (caches de mémoire, fichiers, bases de données, etc.), accélérant ainsi les choses du côté de l'application serveur. Gardez à l'esprit que plus le cookie est gros, plus la charge utile sur le réseau est lourde; vous risquez donc de perdre ce que vous enregistrez dans la recherche de base de données sur le serveur sur le réseau. Réfléchissez bien à ce qu'il faut inclure dans vos cookies.

Pourquoi les cookies doivent-ils être signés?

Les cookies sont utilisés pour conserver toutes sortes d'informations, dont certaines peuvent être très sensibles. De par leur nature, elles ne sont pas non plus sûres et exigent la prise de plusieurs précautions auxiliaires pour être considérées comme sûres de quelque manière que ce soit pour les deux parties, client et serveur. La signature des cookies aborde spécifiquement le problème avec lequel ils peuvent être manipulés lors de tentatives de tromper des applications serveur. Il existe d'autres mesures pour atténuer d'autres types de vulnérabilités, je vous encourage à en lire davantage sur les cookies.

Comment un cookie peut-il être altéré?

Les cookies résident sur le client sous forme de texte et peuvent être modifiés sans effort. Un cookie reçu par votre application serveur pourrait avoir été modifié pour un certain nombre de raisons, dont certaines peuvent ne pas être innocentes. Imaginez une application Web qui conserve les informations d'autorisation de ses utilisateurs sur les cookies et accorde des privilèges en fonction de ces informations. Si le cookie n'est pas protégé contre le bricolage, n'importe qui peut modifier le sien pour passer de "rôle = visiteur" à "rôle = admin" et l'application n'en sera pas plus sage.

Pourquoi un SECRET_KEY Est-il nécessaire pour signer les cookies?

La vérification des cookies est un peu différent de la vérification du code source telle que décrite précédemment. Dans le cas du code source, l'auteur d'origine est le dépositaire et le propriétaire de l'empreinte de référence (la somme de contrôle), qui sera maintenue publique. Ce que vous ne faites pas confiance, c'est le code source, mais vous faites confiance à la signature publique. Donc, pour vérifier votre copie de la source, vous voulez simplement que votre hachage calculé corresponde au hachage public.

Dans le cas d'un cookie, toutefois, l'application ne garde pas trace de la signature, elle garde trace de son SECRET_KEY. Le SECRET_KEY Est l'empreinte digitale de référence. Les cookies voyagent avec une signature qu'ils prétendent être légitime. La légitimité signifie ici que la signature a été émise par le propriétaire du cookie, c'est-à-dire l'application, et dans ce cas, c'est cette affirmation à laquelle vous ne faites pas confiance et vous devez vérifier la validité de la signature. Pour ce faire, vous devez inclure un élément dans la signature que vous ne connaissez que, c'est le SECRET_KEY. Une personne peut changer un cookie, mais comme elle n'a pas l'ingrédient secret nécessaire pour calculer correctement une signature valide, elle ne peut pas l'utiliser. Comme indiqué un peu plus tôt, ce type d’empreinte digitale, où, en plus de la somme de contrôle, fournit également une clé secrète, est appelé code d’authentification de message.

Qu'en est-il des sessions?

Les sessions dans leur implémentation classique sont des cookies qui ne portent qu'un identifiant dans le champ content, le session_id. Le but des sessions est exactement le même que celui des cookies signés, c’est-à-dire pour empêcher la manipulation des cookies. Les sessions classiques ont cependant une approche différente. À la réception d'un cookie de session, le serveur utilise l'ID pour rechercher les données de la session dans son propre stockage local, qui peut être une base de données, un fichier ou parfois un cache en mémoire. Le cookie de session est généralement configuré pour expirer à la fermeture du navigateur. En raison de l'étape de recherche du stockage local, cette implémentation de sessions entraîne généralement un impact négatif sur les performances. Les cookies signés deviennent une alternative privilégiée et c'est ainsi que les sessions de Flask sont mises en œuvre. En d'autres termes, Flask) sessions sont des cookies signés, et pour utiliser des cookies signés dans Flask utilisez simplement son API Session.

Pourquoi ne pas aussi chiffrer les cookies?

Parfois, le contenu des cookies peut être crypté avant que ne soit également signé . Ceci est fait s'ils sont jugés trop sensibles pour être visibles depuis le navigateur (le cryptage masque le contenu). Cependant, la simple signature de cookies répond à un besoin différent, celui de vouloir conserver une certaine visibilité et la facilité d'utilisation des cookies sur le navigateur, tout en évitant qu'ils ne soient manipulés.

Que se passe-t-il si je change le SECRET_KEY?

En modifiant le SECRET_KEY, Vous annulez tous les cookies signés avec la clé précédente. Lorsque l'application reçoit une demande avec un cookie signé avec un précédent SECRET_KEY, Elle tente de calculer la signature avec le nouveau SECRET_KEY, Et les deux signatures ne correspondent pas, ce cookie et toutes ses données seront rejetées, ce sera comme si le navigateur se connectait au serveur pour la première fois. Les utilisateurs seront déconnectés et leur ancien cookie sera oublié, ainsi que tout ce qui est stocké à l'intérieur. Notez que cela diffère de la façon dont un cookie expiré est traité. Le bail d'un cookie expiré peut être prolongé si sa signature est vérifiée. Une signature invalide implique simplement un cookie invalide.

Donc, à moins que vous ne vouliez invalider tous les cookies signés, essayez de conserver le même code SECRET_KEY Pendant de longues périodes.

Qu'est-ce qu'un bon SECRET_KEY?

Une clé secrète devrait être difficile à deviner. La documentation sur Sessions contient une bonne recette pour la génération de clés aléatoires:

>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'

Vous copiez la clé et collez-la dans votre fichier de configuration en tant que valeur de SECRET_KEY.

Sans utiliser une clé générée aléatoirement, vous pouvez utiliser un assortiment complexe de mots, de chiffres et de symboles, éventuellement organisés dans une phrase connue de vous et codée sous forme d'octets.

Ne pas définissez le SECRET_KEY Directement avec une fonction qui génère une clé différente à chaque appel. Par exemple, ne faites pas ceci:

# this is not good
SECRET_KEY = random_key_generator()

Chaque fois que votre application est redémarrée, une nouvelle clé lui est attribuée, ce qui invalide la précédente.

Au lieu de cela, ouvrez un shell interactif python) et appelez la fonction pour générer la clé, puis copiez-la et collez-la dans la configuration.

53
Michael Ekoka