Meilleure approche pour encryption/décryption de mot de passe

Meilleure approche pour encryption/décryption de mot de passe - PHP - Programmation

Marsh Posté le 15-09-2015 à 23:06:03    

Bonjour,
 
Voilà j'ai une application Java à laquelle l'utilisateur doit se logger avec son nom/mot de passe, rien de bien original. Quand il soumet le formulaire (Java toujours), une requête est faite à un serveur web qui retourne ok/pas ok etc...
 
Ma question est toute simple: comment je dois gérer la sécurité de tout ça pour que ce soit basique mais pas trop pourri.
 
- Sans chiffrage, le mot de passe est en clair dans les requêtes (http) et donc si on écoute le réseau on a le mot de passe.
- Avec un chiffrage côté client, il faut être capable soit de déchiffrer le mot de passe côté serveur, soit de comparer cette version chiffrée à la précédente enregistrée dans la DB (sachant que le chiffrage se doit de donner un résultat différent à chaque fois, sinon ça revient à avoir pas de chiffrage).
 
De plus quoi qu'on fasse côté client (chiffrage avec clé etc...), ce sera accessible via une "simple" décompilation du code Java (je sais pas si c'est toujours aussi facile que quelques années en arrière), et donc il sera facile de remonter au mot de passe en ayant intercepté les paquets réseau.
 
Je ne trouve pas de documentation lisible, je n'ai peut-être pas fait les bonnes recherches, mais je n'arrive que sur des sites qui parlent du sujet de manière très complexe, et je n'ai pas vraiment le temps de devenir expert en sécurité. Je pensais que des trucs simples et fonctionnels seraient trouvables comme souvent avec Java.
 
PS: Je parle pas mal de Java mais c'est un problème mixte Java/PHP et fallait choisir l'un des 2 ...
 
Merci de toute aide qui pourra m'aider à dégrossir cette partie de mon application.

Reply

Marsh Posté le 15-09-2015 à 23:06:03   

Reply

Marsh Posté le 16-09-2015 à 00:09:02    

Plusieurs approches, la plus classique:
 
Entre le client et le serveur (à configurer côté serveur):
- chiffrage systématique en HTTPS de tout ce qui transite entre un client et ton serveur. Ce qui évitera les attaques type "man in the middle". Il te faut acheter un certificat SSL auprès d'un presta de confiance, il y en a plein, les plus petits commencent vers 50€/an chez OVH ou gandi par ex. Les plus gros sont vers 1500€/an, chez verisign par exemple.
Tout dépend de ce dont tu as besoin comme garantie, ceux à 50€ souvent suffisent largement.
Pour les tests, tu peux chiffrer en local une clef perso, tu auras un message d'alerte de ton navigateur, mais rien d'autre (a éviter d'utiliser cette clef une fois le système mis en place avec de vrais clients)
 
Côté client:
- Rien à faire de spécial, le HTTPS est déjà là pour ca.
 
Côté serveur:
- Quand un client créé un compte, on hash son mot de passe, ya trois niveaux de sécurité assez classiques:
  - le plus sécure: on génère un salt pour chaque user, ce salt est stocké en BDD a côté du mot de passe hashé, il est unique et suffisamment random (il y a dans chaque languages de quoi obtenir des nombres randoms, genre SecureRandom en java), ne pas utiliser des nombres aléatoires classiques, souvent pas assez random justement...
  - le plus classique: un salt pour tous les utilisateurs, c'est le plus classique car celui qui offre le meilleur rendement vitesse/sécurité. Cela dit, si un mec s'attaque réellement à ton système, il peut se mettre à faire des rainbow table avec le salt, vu qu'il ne change pas, c'est donc plutôt pas si sécure que ca, vaut mieux celle du dessus si possible)
  - le plus risqué: on stocke le hash directement sans salt.
 
Rapidos en code ca donne (version sécure):

Code :
  1. $salt = super_hardcore_random_generator();
  2. $password = $_POST["password"];
  3. $hash = hash("sha256", $salt.$password);
  4. // On stocke $salt et $hash qui sont nécessaire pour le login


 
- Quand un utilisateur veut se logger:
  - le plus sécure: on récupère en BDD l'utilisateur qui a le bon loggin. On prend le mdp qu'il vient d'envoyer, on prend le salt venu de la BDD, et on créer le hash comme lors de la création de l'utilisateur, et compare avec le hash venu de la BDD. Si c'est ok, l'utilisateur est loggé.
  - le plus classique: on prend le mdp venu du client, on prend le salt "global", et on créer le hash, on test directement en BDD que l'on a un couple login/password qui va bien, on valide ou non en conséquence.
  - le plus risqué: on prend le mdp venu du client, on le hash, et on compare login/hash dans la base de données...
 
En code (version sécure):

Code :
  1. $login = $_POST["login"];
  2. $password = $_POST["password"];
  3. $user = sql("SELECT login, salt, password FROM user WHERE login = ? LIMIT 0,1", $login);
  4. $hash = hash("sha256", $user["salt"].$password);
  5. // En partant du principe que $user["password"] contient le hash précédemment calculé avec le salt plus haut
  6. if ($hash === $user["password"]) {
  7. }


 
Avantages divers:
 - HTTPS te garantis que, malgré que les données ne soit pas cryptés du côté de l'utilisateur, elles ne sont pas pour autant lisible jusqu'a l'arrivée à ton serveur (l'autre sens, du serveur au client, est tout aussi vrai).
 - un hash, a la particularité de détruire le mot de passe initial, et il n'est pas possible de revenir en arrière, donc, dans ta base de données, tu as une suite de lettres sur le mot de passe, dont personnes ne peut remonter au vrai mot de passe (ni toi/admin d'ailleurs). Ca garanti une bonne qualité.
 
POUR AUTANT, certaines personnes font ce que l'on appelle des rainbow tables: tu prends un algo de hash genre SHA1, et tu génères toutes les possibilités, genre SHA1("a" ), puis SHA1("b" ) et ainsi de suite. Ils stockent ce couple clef/valeur (donc ils stockents "a" = "ALDDMSD..." ), et ainsi de suite.
=> ca fait que si un utilisateur utilise un mot de passe trop court, ou trop facile à deviner, il est possible d'obtenir le mot de passe initial depuis le hash. Soit, pas du tout ce que tu souhaites.
 
Le salt, qu'il soit sécure ou non, sert pour ce point là. En rajoutant une suite de caractère random devant le mot de passe de l'utilisateur, le principe de la rainbow table s'effondre, car il est très dur de faire ca quand, même si l'utilisateur fournit un mot de passe à 1 caractère, le hash en réalité dérive de 10/20 caractères grace au salt que tu as mis devant le mdp...
 
 
 
Voila, avec ca t'a une base digne de ce nom ;)
 
Pour résumer:
- HTTPS entre le client et le serveur
- salt + stockage du hash(salt + password) en BDD, et avec ca tu as un truc qui fait face au attaques intermédiaire, et autres personnes qui pourraient voler la BDD et tenter de se faire passer pour certains utilisateurs.
 
Ah, et quand un utilisateur perd un mot de passe, tu regénères le salt et un nouveau mot de passe, et renvoi un joli mail avec le mot de passe déchiffré sans le salt bien sur ;)


Message édité par Devil'sTiger le 16-09-2015 à 00:17:07
Reply

Marsh Posté le 16-09-2015 à 11:19:22    

Merci pour cette réponse détaillée.
 
Ceci dit, côté client (une application Java destinée à tourner sous Android) je n'ai pas possibilité en l'état d'utiliser HTTPS (les librairies que j'utilise ne le font pas).
 
Est-ce qu'un chiffrage basé sur un truc style clé publique/clé privée a du sens dans mon cas ?

Reply

Marsh Posté le 16-09-2015 à 11:29:48    

T'es sur que tu n'y a pas accès ?
 
https://developer.android.com/train [...] y-ssl.html
 
Maintenant le refaire, c'est vraiment, vraiment pas évident pour le coups, je serais toi, je tenterais de modifier mon code pour que ca devienne dispo:
- déjà une bibli qui le supporte pas, c'est bof,
- quand bien même elle a une raison précise pour ne pas le supporter, ça n'est pas une si bonne idée de refaire quelque chose à la mano...
 
Cela dit, il y a très longtemps j'avais eu un pb similaire, et pour le coup, impossible d'avoir HTTPS dans mon cas, je me souviens que j'y étais arrivé (non sans mal), en ré-implémentant une partie du protocole, mais ce fut tellement fastidieux (et pour le coup je pourrais pas t'aider, je sais pas ou est passé le code...).

Reply

Marsh Posté le 16-09-2015 à 11:43:47    

Je vais essayer d'utiliser les trucs d'Android qui ont l'air pas mal.
Là je travaille avec "LibGDX" qui fournit des helpers sympas pour HTTP mais rien (que j'ai trouvé en tout cas) pour HTTPS.
 
S'il faut faire avec d'autres trucs pour la partie login j'imagine que c'est mieux que de réinventer la roue. Je vais voir ça.
 
Merci

Reply

Marsh Posté le 16-09-2015 à 14:54:36    

A première vue libdgx supporte bien HTTPS:
 
http://www.badlogicgames.com/forum [...] 11&t=19762
 
Mais il te faut un trusted certificate (donc un certificat payant). T'a une maigre chance avec par exemple StartSSL:
https://www.startssl.com/?lang=fr
 
Le soucis est le suivant; souvent les certificats payants sont ceux supportés (chaque device embarque une liste de certificats "roots" trusted), si pour une raison ton device a pas en "root" ceux de StartSSL, t'a seule chance est d'ajouter manuellement un certificat root venant de StartSSL:
http://stackoverflow.com/questions [...] oid-device
 
Ca semble possible à partir d'android 4.0

Reply

Marsh Posté le 16-09-2015 à 17:25:02    

Merci d'avoir fait la recherche, je suis pas très à l'aise avec tout ça, ça me rend grandement service (je re-découvre le lien entre HTTPS et SSL, c'est dire si je pars de loin :'( ).
 
Je vais faire des tests en local, mais vu que je pars d'une application Java, j'ai un moyen de contrôler que les données sont chiffrées ? J'imagine que tout se fait de manière transparente, mais grosso-modo, si ça fonctionne avec les requêtes sur HTTPS, je peux en conclure que tout est bien chiffré ou il y a une possibilité que ça marche sans pour autant être sécurisé ?
 

Reply

Marsh Posté le 17-09-2015 à 12:28:54    

HTTPS une fois en place c'est transparent, tu "reçois du lisible" et tu "envois du lisible" dans les deux sens sans t'en soucier.
 
Si ca marche pas, tu auras une erreur HTTPS, donc pas vraiment besoin de te soucier du moindre test, tu mets https:// devant les requêtes, et tu croises les doigts pour que la réception soit ce que tu attendais :D

Reply

Marsh Posté le 17-09-2015 à 16:16:19    

OK merci pour toutes ces infos, va falloir que je digère tout ça et que je vois si j'arrive à en faire quelque chose.

Reply

Marsh Posté le 26-09-2015 à 17:31:59    

Pour le hashage de mot de passe, partir sur du sha est maintenant déconseillé par la doc PHP elle même.
Vaut mieux utiliser bcrypt qui a été conçu pour sécuriser les mots de passe contrairement aux hashs


---------------
collectionneur de pâtes thermiques
Reply

Marsh Posté le 26-09-2015 à 17:31:59   

Reply

Marsh Posté le 30-09-2015 à 13:37:10    

À partir de PHP 5.5, il y a l'API password, très simple d'usage :
http://php.net/manual/fr/book.password.php
 
Pour les versions antérieures à PHP 5.5, une librairie de compatibilité existe :
https://github.com/ircmaxell/password_compat
 
Ne jamais stocker de simples hash de mot de passe. Niveau sécurité = 0

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed