web-dev-qa-db-fra.com

PHP meilleures pratiques pour l'authentification des utilisateurs et la sécurité des mots de passe

Quelles sont les meilleures bibliothèques/méthodes actuelles pour authentifier les utilisateurs sans l'utilisation d'un CMS ou d'un framework lourd?

Les réponses doivent inclure des suggestions pour tout ce qui, selon vous, devrait être considéré comme la norme pour le nouveau développement PHP impliquant l'authentification des utilisateurs.

48
Daren Schwenke

OpenID est une méthode pour authentifier les utilisateurs en fonction de leurs comptes existants sur les services Web courants tels que Yahoo, Google et Flickr.

Les connexions à votre site sont basées sur une connexion réussie au site distant.

Vous n'avez pas besoin de stocker des informations utilisateur sensibles ou d'utiliser SSL pour sécuriser les connexions utilisateur.

Une version actuelle PHP version de la bibliothèque peut être trouvée ici .

30
Daren Schwenke

Implémentation de l'authentification des utilisateurs en toute sécurité sans dépendre d'un framework (ou d'une bibliothèque tierce, comme OpenID) pour le faire pour vous n'est pas une entreprise banale.

À une vue d'ensemble de 10000 pieds, vous devez décider:

  • Avez-vous des noms d'utilisateur, des adresses e-mail ou des ID utilisateur comme sélecteur principal?
  • Comment devez-vous stocker les mots de passe? PROTIP: password_hash() ou scrypt sont le chemin à parcourir.
  • Comment devez-vous gérer les cases à cocher "Se souvenir de moi"? Il existe de nombreuses mauvaises stratégies pour cela sur Internet. Traitez chacun d'eux avec scepticisme, car ils pourraient introduire des vulnérabilités dans votre application.
  • Comment l'application doit-elle gérer les utilisateurs qui oublient leur mot de passe?

Les informations contenues dans cette réponse sont pertinentes et à jour au 9 mai 2015 et pourraient être obsolètes par la conclusion du concours de hachage de mot de passe

Sélecteurs primaires

En général, les noms d'utilisateur et adresses e-mail sont meilleurs que les numéros d'identification.

Il ne devrait pas y avoir d'exigence de sécurité pour garder les noms d'utilisateur secrets, car dans la pratique, ils seront divulgués lorsque quelqu'un tentera de s'enregistrer de toute façon.

Vous pouvez décider de traiter ou non les adresses e-mail comme un secret. Les utilisateurs aiment généralement ne pas être exposés aux spammeurs, aux escrocs et aux trolls.

Hachage de mot de passe

Vous devez utiliser password_hash() et password_verify() sauf si vous êtes suffisamment expérimenté dans l'écriture de bibliothèques de cryptographie pour aller au-delà.

Au-delà de Bcrypt

Parfois, les développeurs aiment faire preuve de créativité (par exemple, ajouter un "piment", ce qui signifie généralement un pré-hachage ou des mots de passe HMACing avec une clé statique) et aller au-delà des implémentations standard. Nous l'avons fait nous-mêmes, mais de façon très conservatrice.

Pour nos projets internes (qui ont une marge de sécurité beaucoup plus élevée que la plupart des blogs), nous avons écrit un wrapper autour de cette API appelé PasswordLock qui hache d'abord un mot de passe avec sha256, puis base64 code la sortie de hachage brute, puis transmet ce hachage encodé en base64 à password_hash(), et enfin chiffre le hachage bcrypt avec ne bibliothèque de chiffrement correctement implémentée .

Pour réitérer, au lieu de poivrer, nous chiffrons nos hachages de mot de passe. Cela nous donne plus d'agilité en cas de fuite (nous pouvons déchiffrer puis rechiffrer car nous connaissons la clé). De plus, nous pouvons exécuter notre serveur Web et notre base de données sur du matériel distinct dans le même centre de données pour atténuer l'impact d'une vulnérabilité d'injection SQL. (Pour commencer à craquer les hachages, vous avez besoin de la clé AES. Vous ne pouvez pas l'obtenir de la base de données, même si vous vous échappez vers le système de fichiers.)

// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);

// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
    // Authenticated!
}

Stockage de mot de passe avec PasswordLock:

  1. hash('sha256', $password, true);
  2. base64_encode($step1);
  3. password_hash($step2, PASSWORD_DEFAULT);
  4. Crypto::encrypt($step3, $secretKey);

Vérification du mot de passe avec PasswordLock:

  1. Crypto::decrypt($ciphertext, $secretKey);
  2. hash('sha256', $password, true);
  3. base64_encode($step2);
  4. password_verify($step3, $step1);

Lectures complémentaires

13

J'utilise OpenID .

Mais comme stackoverflow j'utilise le projet Google openid-selector pour faire le gros du travail.
Page de démonstration ici .

Les avantages évidents (d'OpenID) sont.

  • Vous n'avez pas besoin d'être un expert en sécurité.
  • Les utilisateurs font confiance aux grands sites avec leurs informations.
  • Vous pouvez demander des choses comme (surnom, etc.) mais l'utilisateur doit accepter.
  • Vous n'avez pas à vous soucier de:
    • processus d'inscription
    • mot de passe perdu/oublié
11
Martin York

Beaucoup de bonnes réponses ici, mais je pense que cela vaut la peine de le dire --N'essayez PAS de réinventer la roue dans ce cas! Il est extrêmement facile de bousiller l'authentification des utilisateurs de différentes manières. À moins que vous vraiment ayez besoin d'une solution personnalisée et ayez une connaissance ferme des schémas de sécurité et des meilleures pratiques, vous aurez presque certainement des failles de sécurité.

OpenID est génial, ou si vous allez lancer le vôtre, utilisez au moins une bibliothèque établie et suivez la documentation!

9
DougW

PHPass est une bibliothèque de hachage de mot de passe légère et à coût variable utilisant bcrypt.

Le coût variable signifie que vous pouvez augmenter le "coût" du hachage des mots de passe pour augmenter la sécurité de manière transparente sans avoir à invalider vos mots de passe utilisateur hachés précédemment.

La taille de champ utilisée pour le stockage du hachage est constante même lors de l'augmentation du "coût" en raison de l'augmentation non pas de la taille du hachage, mais du nombre d'itérations nécessaires pour le produire.

8
Daren Schwenke

Connectez-vous en utilisant HTTP AUTH

  1. Utilisation d'Apache: http://httpd.Apache.org/docs/2.2/howto/auth.html
  2. Il est également possible avec IIS et autres serveurs Web .

Une fois authentifié, pour PHP , il vous suffit d'utiliser $_SERVER['PHP_AUTH_USER'] pour récupérer le nom d'utilisateur utilisé lors de l'authentification.

Cela peut être une solution plus rapide et, parfois, plus flexible que la gestion de la solution au niveau des scripts, à condition que des informations limitées soient nécessaires concernant l'utilisateur car tout ce qui est mis à votre disposition est le nom d'utilisateur utilisé pour vous connecter.

Cependant, oubliez d'intégrer votre authentification dans un formulaire HTML à moins que vous n'implémentiez un schéma HTTP AUTH complet à partir de votre langage de script (comme décrit ci-dessous).

Déplacement de votre propre HTTP AUTH dans votre langage de script

Vous pouvez réellement étendreHTTP Basic Auth en l'émulant in votre langage de script. La seule exigence pour cela est que votre langage de script doit pouvoir envoyer des en-têtes HTTP au client HTTP. Une explication détaillée sur la façon d'accomplir ceci en utilisant PHP peut être trouvée ici: ( voir plus sur PHP et HTTP AUTH ).

Vous pouvez développer l'article ci-dessus en utilisant un schéma d'authentification typique, un magasin de fichiers, même PHP sessions ou cookies (si les informations ne doivent pas être persistantes), vous offrant beaucoup plus de flexibilité lors de l'utilisation de HTTP AUTH, tout en conservant une certaine simplicité.

Inconvénients de HTTP AUTH

  1. Le principal inconvénient de l'authentification HTTP est les complications que la déconnexion peut avoir. La principale façon d'effacer la session de l'utilisateur est de fermer le navigateur ou de faire passer un en-tête avec l'authentification 403 requise. Malheureusement, cela signifie que la fenêtre contextuelle HTTP AUTH revient sur la page et oblige les utilisateurs à se reconnecter ou à annuler. Cela peut ne pas fonctionner correctement lorsque l'on tient compte de l'utilisabilité, mais peut être contourné avec des résultats intéressants (par exemple, en utilisant une combinaison de cookies et HTTP AUTH pour stocker l'état).

  2. Les popups HTTP AUTH, la session et la gestion des en-têtes HTTP sont déterminés par l'implémentation du navigateur de la norme. Cela signifie que vous serez bloqué avec cette implémentation (y compris tout bogue) sans possibilité de solution de contournement (contrairement à d'autres alternatives).

  3. L'authentification de base signifie également que l'utilisateur_auth et le mot de passe apparaissent dans les journaux du serveur, puis vous devez utiliser https pour tout, car sinon le nom d'utilisateur et le mot de passe passent également sur le réseau à chaque requête en texte brut.

5
Patrick Allaert

Il est important de séparer la couche de sécurité de votre application du reste. S'il n'y a pas de distance entre votre logique d'application et votre système de communication, vous êtes libre de communiquer de manière non sécurisée à un endroit et en toute sécurité ailleurs. Vous allez peut-être faire une erreur et envoyer un mot de passe dans un cookie non chiffré, ou peut-être oublierez-vous de vérifier les informations d'identification de l'utilisateur pour une étape. Sans une "bonne façon" de communiquer avec l'utilisateur, vous êtes sûr de faire une erreur.

Par exemple, disons que c'est ainsi que vous vérifiez les utilisateurs maintenant:

user_cookie = getSecureCookie()
if (user_cookie.password == session_user.password) {
    do_secure_thing()
    ...
}

Si une vulnérabilité est découverte dans getSecureCookie () et que vous utilisez ce code pour vérifier les utilisateurs dans votre application, vous ne trouverez peut-être pas toutes les instances de getSecureCookie () qui doivent être corrigées. Si toutefois vous séparez votre logique de votre sécurité:

if (userVerified()) {
    do_secure_thing()
    ...
}

... vous pourrez sécuriser rapidement et facilement votre application. Donnez-vous une "bonne façon" de faire de la sécurité, et vous serez beaucoup moins susceptible de faire une erreur de sécurité majeure.

4
Evan Kroske

La meilleure authentification consiste à utiliser l'authentification multifacteur, idéalement une version sans jeton sur toutes les connexions sensibles à la sécurité.

Mot de passe protégé et plus facile à utiliser avec une fiabilité et une sécurité élevées. Plusieurs sont disponibles au-delà d'EMC/RSA. Je préfère le PINSafe de SwivelSecure.

Igor S

1
Igor Sill