Comment envoyer un mot de passe en toute sécurité via HTTP?

115

Si sur un écran de connexion l'utilisateur soumet un formulaire avec son nom d'utilisateur et son mot de passe, le mot de passe est envoyé en texte brut (même avec POST, corrigez-moi si je me trompe).

La question est donc de savoir quelle est la bonne façon de protéger l'utilisateur et son mot de passe contre le tiers qui pourrait écouter les données de communication?

Je sais que HTTPS est une solution au problème, mais existe-t-il un moyen d'assurer au moins un certain niveau de sécurité en utilisant le protocole HTTP standard (requête POST)? (peut-être en utilisant javascript d'une manière ou d'une autre)

EDIT J'ai peut-être oublié certaines choses importantes.

Ce dont je parlais était une page - c'est une page de connexion générée par PHP, qui est bien sûr envoyée à l'utilisateur dans une requête HTTP GET sous forme de fichier HTML. Il n'y a pas de connexion (@Jeremy Powel) établie entre le serveur et le client, donc je ne peux pas créer un tel protocole d'établissement de liaison. Et je veux que le processus complet soit transparent pour l'utilisateur - il veut soumettre un mot de passe, pas s'occuper de la cryptographie.

Merci.

Kornelije Petak
la source
1
Vous ne pourrez probablement pas accomplir cela sans que le client n'utilise la cryptographie, mais l'utilisateur n'a pas à voir un tel processus. Il saisit simplement son mot de passe et le code généré par votre PHP (javascript par exemple) gère tout pour vous.
Jeremy Powell
13
Le problème que vous décrivez est la raison pour laquelle HTTPS a été inventé. Si vous envoyez un secret au client pour crypter le mot de passe, un espion pourra le renifler et décrypter le mot de passe au retour.
jnoss
1
Donc S dans votre suggestion pourrait être uniquement mot de passe (ou nom d'utilisateur + mot de passe combinés de quelque manière que ce soit), car c'est le seul "secret" dont dispose l'utilisateur. Ai-je raison? La solution serait donc la suivante: - Le serveur fournit à la page HTML un champ de formulaire caché R - L'utilisateur entre le mot de passe, et avant l'envoi du mot de passe, le javascript calcule H (R, S) et l'envoie au serveur, peut-être même en utilisant AJAX - Le serveur calcule H (R, S) et le compare avec reçu et envoie une réponse à la demande ajax si l'authentification a réussi - Le javascript redirige le navigateur vers la page Web souhaitée
Kornelije Petak
2
@jeremy powell - bien que ce que vous décrivez soit une pratique courante, il est également vulnérable à un intermédiaire qui peut renifler le cookie à partir d'un en-tête et se faire passer pour l'utilisateur en réutilisant le cookie. Il est difficile de se protéger contre les attaques de l'homme du milieu, sauf si vous utilisez HTTPS
jnoss
1
Pour quiconque répondra à cette question à l'avenir: APRÈS vous être connecté, vous devez également sécuriser le cookie de session. (Donc: utiliser HTTPS est vraiment beaucoup plus facile.)
Arjan

Réponses:

66

Utiliser HTTP avec SSL vous facilitera la vie et vous pourrez vous reposer à l'aise. Des personnes très intelligentes (plus intelligentes que moi du moins!) Ont scruté cette méthode de communication confidentielle pendant des années.

Jeremy Powell
la source
14
... et "Mais je dois payer pour un certificat SSL !!" n'est pas une plainte valide, car vous pouvez les obtenir pour 30 $ ces jours-ci. Vos données ne valent vraiment pas 30 dollars à protéger?
caf
3
Que faire si l'hôte Web auquel vous vous êtes abonné ne prend pas en charge l'ajout de certificats SSL?
Calmarius
89
@Calmarius - puis vous passez à un vrai hébergeur
BornToCode
3
@BornToCode Cela signifie techniquement que vous devez avoir une adresse IP dédiée et que vous devez posséder le matériel du serveur (ou au moins un VPS) pour utiliser HTTPS. Les hébergeurs partagés ne peuvent pas utiliser HTTPS, sauf si le serveur entier est protégé par le certificat du propriétaire de l'hôte.
Calmarius
6
les hébergeurs partagés peuvent certainement faire https, en utilisant en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton
39

L'authentification sécurisée est un vaste sujet. En un mot, comme @ jeremy-powell l'a mentionné, privilégiez toujours l'envoi d'informations d'identification via HTTPS au lieu de HTTP. Cela enlèvera beaucoup de maux de tête liés à la sécurité.

Les certificats TSL / SSL sont plutôt bon marché de nos jours. En fait, si vous ne voulez pas du tout dépenser d'argent, il y a un letsencrypt.org gratuit - une autorité de certification automatisée.

Vous pouvez aller plus loin et utiliser caddyserver.com qui appelle letsencrypt en arrière-plan.

Maintenant, une fois que nous avons éliminé HTTPS ...

Vous ne devez pas envoyer de login et de mot de passe via la charge utile POST ou les paramètres GET. Utilisez plutôt un en-tête d'autorisation (schéma d'authentification d'accès de base), qui est construit comme suit:

  • Le nom d'utilisateur et le mot de passe sont combinés dans une chaîne séparée par deux-points, par exemple: nom d'utilisateur: mot de passe
  • La chaîne résultante est codée à l'aide de la variante RFC2045-MIME de Base64, sauf qu'elle n'est pas limitée à 76 caractères / ligne.
  • La méthode d'autorisation et un espace c'est-à-dire "Basic" sont alors placés avant la chaîne codée.

source: Wikipedia: en-tête d'autorisation

Cela peut sembler un peu compliqué, mais ce n'est pas le cas. Il existe de nombreuses bonnes bibliothèques qui vous fourniront cette fonctionnalité prête à l'emploi.

Il y a quelques bonnes raisons pour lesquelles vous devriez utiliser un en-tête d'autorisation

  1. C'est un standard
  2. C'est simple (après avoir appris à les utiliser)
  3. Cela vous permettra de vous connecter au niveau de l'URL, comme ceci: https://user:[email protected]/login(Chrome, par exemple, le convertira automatiquement en en- Authorizationtête)

IMPORTANT:
comme indiqué par @zaph dans son commentaire ci-dessous, envoyer des informations sensibles en tant que requête GET n'est pas une bonne idée car cela finira probablement dans les journaux du serveur.

entrez la description de l'image ici

FullStackForger
la source
11
Le problème avec l'envoi d'informations d'identification (mot de passe) en tant que paramètres GET est que la paire utilisateur / mot de passe se retrouvera probablement dans les journaux du serveur, ce qui n'est pas une bonne idée. Il est préférable d'envoyer les informations d'identification dans un POST.
zaph
Ahh ... pas du tout. La capture d'écran que vous voyez est modifiée pour illustrer ce qui se passe dans un navigateur. Le moment où vous appuyez sur entrer dans le navigateur convertira votre URL en créant un en- Authorizationtête. Essayez-le. Les journaux rappelleront propre. Et bien sûr, si vous passez un appel depuis le serveur (si c'est le scénario qui vous préoccupe), vous devez bien sûr générer un en-tête par programme.
FullStackForger
Vous ne pouvez pas enregistrer ce que vous ne pouvez pas voir. username:password@urldu navigateur se traduit par: url+ en- Authorizationtête de demande. Quant aux requêtes GET ... comme je l'ai dit, utilisez l'en-tête Authroziation. Il est préférable.
FullStackForger
2
Vous n'abordez pas le point de la question: protéger les données sensibles contre les écoutes indiscrètes. L'objectif n'est pas de trouver un moyen alternatif et / ou plus standardisé de transmettre les informations d'identification, mais de les protéger via un canal non sécurisé.
Lord of the Goo
3
Il convient de souligner que cette solution ne fonctionne que si vous cryptez déjà la connexion avec TLS / SSL. base64 n'est pas un cryptage.
Scot
14

Vous pouvez utiliser un schéma de réponse au défi. Dites que le client et le serveur connaissent tous deux un secret S. Ensuite, le serveur peut être sûr que le client connaît le mot de passe (sans le révéler) en:

  1. Le serveur envoie un nombre aléatoire, R, au client.
  2. Le client renvoie H (R, S) au serveur (où H est une fonction de hachage cryptographique, comme SHA-256)
  3. Le serveur calcule H (R, S) et le compare à la réponse du client. S'ils correspondent, le serveur sait que le client connaît le mot de passe.

Éditer:

Il y a un problème ici avec la fraîcheur de R et le fait que HTTP est sans état. Cela peut être géré en demandant au serveur de créer un secret, appelez-le Q, que seul le serveur connaît . Ensuite, le protocole va comme ceci:

  1. Le serveur génère un nombre aléatoire R. Il envoie ensuite au client H (R, Q) (qui ne peut pas être falsifié par le client).
  2. Le client envoie R, H (R, Q) et calcule H (R, S) et renvoie tout cela au serveur (où H est une fonction de hachage cryptographique, comme SHA-256)
  3. Le serveur calcule H (R, S) et le compare à la réponse du client. Ensuite, il prend R et calcule (à nouveau) H (R, Q). Si la version du client de H (R, Q) et H (R, S) correspond au recalcul du serveur, le serveur considère que le client est authentifié.

A noter, puisque H (R, Q) ne peut pas être falsifié par le client, H (R, Q) agit comme un cookie (et pourrait donc être implémenté en fait comme un cookie).

Une autre modification:

La modification précédente du protocole est incorrecte car quiconque a observé H (R, Q) semble être en mesure de le rejouer avec le hachage correct. Le serveur doit se souvenir quels R ne sont plus récents. Je suis en train de préparer cette réponse pour que vous puissiez modifier cela et trouver quelque chose de bien.

Jeremy Powell
la source
+1 - vous devrez calculer la réponse côté client avec javascript (ou Flash / Silverlight / etc.)
orip
10
N'arrête pas l'homme au milieu ou les attaques d'usurpation d'identité. Par exemple via le wifi. On dirait que cela donnera juste un faux sentiment de sécurité, OMI.
Tom Hawtin - Tackline
2
Cela protège contre les attaques passives, mais un homme du milieu peut toujours attaquer.
Douglas Leeder
7
En outre, il faut que le serveur connaisse le mot de passe d'origine.
Douglas Leeder
3
Ne réinventez pas la crypto! (en production)
bryanph
11

Si votre hébergeur le permet, ou si vous devrez gérer des données sensibles, utilisez HTTPS, point final. (C'est souvent requis par la loi afaik).

Sinon, si vous voulez faire quelque chose via HTTP. Je ferais quelque chose comme ça.

  1. Le serveur intègre sa clé publique dans la page de connexion.
  2. Le client remplit le formulaire de connexion et clique sur Soumettre.
  3. Une requête AJAX obtient l'horodatage actuel du serveur.
  4. Le script côté client concatène les informations d'identification, l'horodatage et un sel (haché à partir de données analogiques, par exemple les mouvements de la souris, les événements de pression de touche), le chiffre à l'aide de la clé publique.
  5. Soumet le hachage résultant.
  6. Le serveur déchiffre le hachage
  7. Vérifie si l'horodatage est suffisamment récent (autorise une courte fenêtre de 5 à 10 secondes uniquement). Rejette la connexion si l'horodatage est trop ancien.
  8. Stocke le hachage pendant 20 secondes. Rejette le même hachage pour la connexion pendant cet intervalle.
  9. Authentifie l'utilisateur.

Ainsi, le mot de passe est protégé et le même hachage d'authentification ne peut pas être rejoué.

À propos de la sécurité du jeton de session. C'est un peu plus difficile. Mais il est possible de rendre la réutilisation d'un jeton de session volé un peu plus difficile.

  1. Le serveur définit un cookie de session supplémentaire qui contient une chaîne aléatoire.
  2. Le navigateur renvoie ce cookie à la prochaine demande.
  3. Le serveur vérifie la valeur dans le cookie, si elle est différente, alors il détruit la session, sinon tout va bien.
  4. Le serveur redéfinit le cookie avec un texte différent.

Ainsi, si le jeton de session a été volé et qu'une demande est envoyée par quelqu'un d'autre, à la prochaine demande de l'utilisateur d'origine, la session sera détruite. Donc, si l'utilisateur navigue activement sur le site, en cliquant souvent sur des liens, le voleur n'ira pas loin avec le jeton volé. Ce schéma peut être renforcé en exigeant une autre authentification pour les opérations sensibles (comme la suppression de compte).

EDIT: Veuillez noter que cela n'empêche pas les attaques MITM si l'attaquant configure sa propre page avec une clé publique différente et envoie des requêtes proxy au serveur. Pour se protéger contre cela, la clé publique doit être épinglée dans le stockage local du navigateur ou dans l'application pour détecter ce type d'astuces.

À propos de l'implémentation: RSA est probablement l'algorithme le plus connu, mais il est assez lent pour les longues clés. Je ne sais pas à quelle vitesse une implémentation PHP ou Javascript serait. Mais il existe probablement des algorithmes plus rapides.

Calmaire
la source
Dans ce cas, le mot de passe est-il vraiment protégé? Est-ce que quelqu'un ne pourrait pas flairer ce qui est envoyé et le déchiffrer à l'aide de la clé publique, puis simplement mettre à jour l'horodatage lorsqu'il l'utilisera plus tard? Est-ce que je manque quelque chose?
michaellindahl
Le cryptage asymétrique @michaellindahl signifie que seule la clé privée - qui ne quitte jamais le serveur - peut être utilisée pour décrypter les choses. Les clés publiques ne peuvent être utilisées que pour crypter.
Dan Pantry
2
Un ordinateur entre le navigateur et le serveur pourrait changer la clé publique sur la page de connexion.
Antti
Merci de partager vos méthodes, j'ai trouvé tout ce qui est très intéressant. L'horodatage ajouté lors de l'envoi des identifiants est une bonne prise! Une question sur l'utilisation d'un cookie de session supplémentaire dont la valeur est une chaîne aléatoire: est-ce comme un jeton pour la requête suivante uniquement?
Victor le
4

J'utiliserais un système d'échange de clés Diffie-Hellman côté serveur et côté client avec AJAX ou plusieurs formulaires (je recommande le premier), bien que je ne vois aucune bonne implémentation de celui-ci sur Internet. N'oubliez pas qu'une bibliothèque JS peut toujours être corrompue ou modifiée par MITM. Le stockage local peut être utilisé pour lutter contre cela, dans une certaine mesure.

nanofarad
la source
4

Vous pouvez utiliser SRP pour utiliser des mots de passe sécurisés sur un canal non sécurisé. L'avantage est que même si un attaquant renifle le trafic ou compromet le serveur, il ne peut pas utiliser les mots de passe sur un autre serveur. https://github.com/alax/jsrp est une bibliothèque javascript qui prend en charge les mots de passe sécurisés via HTTP dans le navigateur ou côté serveur (via le nœud).

Brian Minton
la source
1

HTTPS est si puissant car il utilise une cryptographie asymétrique. Ce type de cryptographie vous permet non seulement de créer un tunnel crypté, mais vous pouvez également vérifier que vous parlez à la bonne personne et non à un pirate informatique.

Voici le code source Java qui utilise le chiffrement asymétrique RSA (utilisé par PGP) pour communiquer: http://www.hushmail.com/services/downloads/

tour
la source
0

vous pouvez utiliser ssl pour votre hôte, il existe un projet gratuit pour ssl comme letsencrypt https://letsencrypt.org/

mk990
la source
2
Vérifiez la troisième phrase en question. (De plus, lisez toujours les autres réponses pour vous assurer de ne pas ajouter de doublon moins détaillé.)
Nathan Tuggy
0

Utiliser https semble la meilleure option ici (les certificats ne sont pas si chers de nos jours). Cependant, si http est une exigence, vous pouvez utiliser une certaine inscription - encrivez-la côté serveur et décrivez-la dans le navigateur des utilisateurs (envoyez la clé séparément).

Nous l'avons utilisé lors de l'implémentation de safevia.net - l'inscription se fait du côté des clients (émetteur / récepteur), de sorte que les données des utilisateurs ne sont pas disponibles sur la couche réseau ou serveur.

parvuselephantus
la source