Je ne suis pas un expert en cybersécurité mais juste un webmaster et je me demande si ce type d'authentification serait dangereux. Je teste le mot de passe comme ceci du côté serveur en utilisant PHP:
if (isset($_POST['pass_Word']) AND $_POST['pass_Word'] == $passwd)
$passwd
vient de ma base de données PostgreSQL. Je pensais au moins que je ne risquais pas l'injection SQL. Dois-je risquer un autre type d'injection? S'il s'agit d'une méthode d'authentification dangereuse, veuillez expliquer pourquoi.
Il semble que vous stockiez les mots de passe en clair, ce qui est une mauvaise idée. Vous devez vous assurer que les mots de passe sont protégés en utilisant, au minimum, password_hash()
et password_verify()
, qui utilisent bcrypt = sous le capot. C'est simple, facile, sûr et parfaitement acceptable pour la plupart des scénarios.
Alternativement, vous pouvez utiliser une méthode légèrement plus sécurisée telle que Argon2 , qui a remporté le Password Hashing Competition et est résistante à la fissuration du CPU et du GPU, et vise également à minimiser le potentiel de attaques latérales. Il y a n article qui explique comment utiliser Argon2 dans le cadre de libsodium PHP wrapper, ou directement en utilisant la bibliothèque "Halite" de Paragon, qui propose Argon2 avec un cryptage symétrique en plus de empêcher l'accès à la base de données uniquement de fournir des hachages utilisables, car la clé symétrique est stockée sur le disque du serveur en tant que fichier. Cette option est plus compliquée, mais elle offre une sécurité supplémentaire si vous êtes vraiment paranoïaque. Je vous conseille toutefois d'éviter cela si vous n'êtes pas familier avec le développement sécurisé, car les chances de vous gâcher quelque chose sont augmentées.
Je recommanderais également d'utiliser ===
afin d'éviter des cas étranges de fausse égalité en utilisant tableaux dans les requêtes URL ou nulls.
réponse du polynôme est parfait. Je voulais signaler d'autres vulnérabilités potentielles: priorité des opérateurs, facilité de révision et facilité de test.
Quelque chose de la forme foo AND bar == baz
est vulnérable aux erreurs de priorité. J'examinerais attentivement qu'en examinant, il y a une longue histoire de mesures de sécurité déjouées en raison des conditions complexes et de la priorité.
Maintenant, il n'y a rien mal avec ce que vous avez écrit, mais il est très facile de se tromper. Dans la plupart des langues, c'est bien parce que opérateurs de comparaison comme ==
ont une priorité plus élevée que les opérateurs logiques comme AND
, donc votre condition se lit comme (notez les parens explicites):
isset($_POST['pass_Word']) AND
($_POST['pass_Word'] == $passwd)
... mais il est très facile de se tromper. Par exemple, AND
et &&
n'ont pas la même priorité. Que se passe-t-il si au lieu d'utiliser isset
vous (ou quelqu'un venant après vous) avez utilisé un raccourci logique ou pour définir une valeur par défaut? (Ce n'est pas équivalent à isset
, c'est juste un exemple de priorité provoquant des gaffes de sécurité)
$_POST['pass_Word'] || '' == $passwd
Cette ligne gotcha est en fait la suivante:
$_POST['pass_Word'] || ('' == $passwd)
Désormais, toute personne possédant un mot de passe vierge, peut-être à la suite d'une erreur de récupération, se connectera toujours.
En ce qui concerne le code sécurisé, expliquez clairement vos parens pour faire connaître votre intention au réviseur et au programme.
Mieux encore, évitez les conditions composées entièrement en code sécurisé. Vous ne pouvez pas bousiller en utilisant ce que vous n'avez pas utilisé. Par exemple, ce code tire parti de l'encapsulation et retour anticipé pour fournir des méthodes de révision et de test très faciles.
// This deals with input and normalizing it.
function can_login($user) {
if( !isset($_POST['pass_Word']) ) {
// Or it could throw an exception to give the
// caller more information about why they didn't login
return false;
}
return check_password($user, $_POST['pass_Word']);
}
// This only deals with checking a password.
// Don't use this, it still has all the flaws Polynomial
// pointed out.
function check_password($user, $check) {
// get_password() should throw an exception if it cannot
// find that user's password to avoid accidentally thinking
// their password is false or 0 or '' or something. This
// avoids relying on the caller doing the check for failure.
return $check === get_password($user);
}
Ce n'est peut-être pas la meilleure méthode, mais elle est petite et facile à tester et à réviser. Cela sépare les détails de la connexion d'un utilisateur (qui peut être plus qu'une vérification de mot de passe, comme s'ils sont un utilisateur valide) de la vérification de leur mot de passe. Tous les problèmes peuvent être repérés et résolus sans avoir à parcourir le reste du code de connexion. Un réviseur vérifiera get_password
et tous les lieux check_password
et can_login
sont utilisés.
Je ne saurais trop insister sur l'importance d'isoler vos composants sécurisés en un morceau aussi petit que possible, en utilisant un code aussi simple que possible, pour les rendre faciles à examiner et à tester.
[~ # ~] bonus [~ # ~]: Voici quelque chose que j'ai pensé faire, mais j'ai décidé que ce serait sécuriser le code moins.
Mon idée originale était d'avoir une fonction qui renvoyait plusieurs valeurs: ils ne fournissaient pas de mot de passe, leur mot de passe était faux, leur mot de passe était correct. Cela permettrait à l'appelant de faire la différence entre "le mot de passe est incorrect" et "il n'a pas fourni de mot de passe, quelque chose ne va pas".
function can_login($user) {
if( !isset($_POST['pass_Word']) ) {
return NO_PASSWORD;
}
$password = get_password($user);
if( $_POST['pass_Word'] === $password ) {
return YES;
}
else {
return NO;
}
}
Et puis vous l'appelez ainsi:
$rslt = can_login($user);
if( $rslt == YES ) {
echo "Login!\n";
}
else if( $rslt == NO ) {
echo "Wrong password.\n";
}
else if( $rslt == NO_PASSWORD ) {
echo "No password given.\n";
}
Le problème est qu'il rend plus compliqué d'appeler correctement la routine. Pire encore, si vous ne lisez pas les documents, vous penseriez que c'était ceci:
if( can_login($user) ) {
echo "Yes!\n";
}
else {
echo "No!\n";
}
Depuis can_login
renvoie toujours une vraie valeur, maintenant tout le monde peut se connecter.
Cela fait ressortir l'essentiel: rendre votre code sécurisé aussi simple et infaillible que possible pour le réviseur, le testeur et l'appelant. Dans ce cas, les exceptions sont la bonne solution car elles fournissent un canal pour obtenir plus d'informations tout en conservant can_login
un simple booléen. Si vous oubliez de vérifier, le programme peut se bloquer, mais la connexion échoue.