web-dev-qa-db-fra.com

Mettre un mot de passe dans un appel API REST

Supposons que j'ai une API REST qui est également utilisée pour définir/réinitialiser les mots de passe. Supposons également que cela fonctionne sur une connexion HTTPS. Y a-t-il une bonne raison de ne pas mettre ce mot de passe dans le chemin d'appel , disons aussi que je vais l'encoder en BASE64?

Un exemple serait de réinitialiser un mot de passe comme celui-ci:

http://www.example.com/user/joe/resetpassword/OLDPASSWD/NEWPASSWD

Je comprends que BASE64 n'est pas un cryptage, mais je veux seulement protéger le mot de passe pour surfer sur l'épaule dans ce cas.

33
Bart Friederichs

Un bon serveur enregistre toutes les requêtes qui lui sont envoyées, y compris les URL (souvent, sans partie variable après '?'), L'adresse IP source, le temps d'exécution ... Voulez-vous vraiment que ce journal (potentiellement lu par un large groupe d'administrateurs) contienne des informations sécurisées en tant que mots de passe? Base64 n'est pas un frein contre eux.

78
Netch

Ce que vous proposez n'est ni sécurisé ni RESTful.

@Netch a déjà mentionné le problème des journaux, mais il y a aussi un autre problème dans le fait que vous montrez les mots de passe envoyés par HTTP, ce qui rend trivial la capture de mots de passe avec n'importe quel type de renifleur de fil ou d'attaque de l'homme du milieu.

Lorsque vous effectuez une demande GET à l'aide de REST, les différents éléments de l'URL représentent des éléments plus fins. Votre URL se lit comme si vous renvoyiez une partie NEWPASSWD d'un OLDPASSWD faisant partie d'un mot de passe de réinitialisation. Cela n'a aucun sens sémantique. Les GET ne doivent pas être utilisés pour enregistrer des données.

Vous devriez faire quelque chose comme ça:

POST https://www.example.com/user/joe/resetpassword/
{oldpasswd:[data], newpasswd:[data]}

POST parce que vous écrivez des données et https parce que vous ne voulez pas qu'elles soient reniflées.

(C'est vraiment la sécurité de la barre basse. Le minimum absolu que vous devriez faire.)

72
Gort the Robot

Le schéma proposé présente des problèmes dans plusieurs domaines.

Sécurité

Les chemins d'URL sont fréquemment enregistrés; mettre des mots de passe non hachés dans le chemin est une mauvaise pratique.

[~ # ~] http [~ # ~]

Les informations d'authentification/autorisation doivent apparaître dans l'en-tête d'autorisation. Ou potentiellement, pour les éléments basés sur un navigateur, l'en-tête Cookie.

[~ # ~] reste [~ # ~]

Les verbes tels que resetpassword dans votre URL sont généralement un signe clair d'un paradigme de transfert d'état non représentatif. Une URL doit représenter une ressource. Que signifie GET resetpassword? Ou SUPPRIMER?

[~ # ~] api [~ # ~]

Ce schéma nécessite de toujours connaître le mot de passe précédent. Vous voudrez probablement autoriser plus de cas; par exemple. le mot de passe est perdu.


Vous pouvez utiliser authentification de base ou Digest , qui sont des schémas bien compris.

PUT /user/joe/password HTTP/1.0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: text/plain
Host: www.example.com

NEWPASSWD

Il ne met pas d'informations ultra-sensibles dans le chemin et suit les conventions HTTP et REST.

Si vous devez autoriser un autre mode d'autorisation (par exemple, un jeton envoyé via un canal vérifié pour réinitialiser le mot de passe), vous pouvez simplement utiliser un en-tête d'autorisation différent sans avoir à changer quoi que ce soit d'autre.

60
Paul Draper

Le problème est d'éviter les mots de passe en texte brut dans vos demandes. Il existe deux options pour répondre aux exigences de service Web reposantes.

1. Hachage côté client

  • Je suppose que vous stockez vos mots de passe comme e. g. hachage (mot de passe + sel)
  • Vous pouvez hacher le nouveau mot de passe avec un sel du côté client
  • Cela signifie: créer un nouveau sel côté client, créer un hachage e. g. hachage (newPassword + newSalt)
  • Envoyez le nouveau hachage créé plus le sel à votre service Web reposant
  • Envoyer l'ancien mot de passe également en tant que hachage (oldPassword + oldSalt)

2. Cryptage

  • Créer une ressource "clé unique" (otk) pour un utilisateur comme/otk/john
  • Cette ressource renvoie une clé unique unique, aléatoire et sécurisée, e. g. kbDlJbmNmQ0Y0SmRHZC9GaWtRMW0ycVJpYzhMcVNZTWlMUXN6ZWxLdTZESFR et un ID unique e. g. 95648915125
  • Votre service Web reposant doit stocker cette otk aléatoire pour la prochaine communication sécurisée avec l'ID 95648915125
  • Chiffrez votre nouveau et ancien mot de passe avec l'otk e. g. AES (pour des raisons de sécurité, vous devez utiliser deux otks distincts pour l'ancien et le nouveau mot de passe)
  • Envoyez les mots de passe cryptés à votre ressource de changement de mot de passe avec l'ID 95648915125
  • Une combinaison otk et ID est autorisée à fonctionner une seule fois, vous devez donc supprimer cette combinaison après avoir changé le mot de passe
  • Meilleure option possible: envoyer le mot de passe actuel/ancien par Basic-Auth.

Remarque: HTTPS est requis pour les deux options!

4
maz258

En dehors de la sécurité, le problème est que ce n'est pas une approche très RESTful.

OLDPASSWD et NEWPASSWD ne représentent rien dans votre hiérarchie de ressources et pire encore, l'opération n'est pas idempotente.

Vous ne pouvez donc utiliser que POST comme verbe, et vous ne devez pas inclure les deux mots de passe dans votre chemin d'accès aux ressources.

4
biziclop

Quelles sont les fonctionnalités d'une opération de réinitialisation de mot de passe?

  1. Ça change quelque chose.
  2. Il y a une valeur à laquelle il est défini.
  3. Seules certaines personnes sont autorisées à le faire (l'utilisateur, un administrateur ou l'un ou l'autre, peut-être avec des règles différentes sur la façon dont l'un ou l'autre peut le faire).

Le point 1 ici signifie que vous ne pouvez pas utiliser GET, vous devez soit POST quelque chose représentant l'opération de changement de mot de passe vers un URI représentant une ressource qui gère les changements de mot de passe, soit PUT quelque chose représentant le nouveau mot de passe vers un URI représentant le mot de passe ou représentant quelque chose (par exemple l'utilisateur) dont ce mot de passe est une caractéristique.

En général, nous POSTONS, notamment parce que cela peut être gênant de METTRE quelque chose que nous ne pourrons PAS OBTENIR plus tard et bien sûr, nous ne pourrons PAS OBTENIR le mot de passe.

Le point 2 sera donc des données représentant le nouveau mot de passe, dans ce qui est POSTé.

Le point 3 signifie que nous devrons autoriser la demande, ce qui signifie que si l'utilisateur est l'utilisateur actuel, nous aurons besoin que le mot de passe actuel nous soit prouvé (bien que nous ne recevions pas nécessairement le mot de passe actuel, si par exemple un défi basé sur le hachage). a été utilisé pour prouver sa connaissance sans l'envoyer).

L'URI doit donc être quelque chose comme <http://example.net/changeCurrentUserPassword> ou <http://example.net/users/joe/changePassword>.

Nous pouvons décider que nous voulons recevoir le mot de passe actuel dans les données POST ainsi que dans le mécanisme d'autorisation général utilisé.

2
Jon Hanna