Comment sécuriser mon PHP le système de connexion?
Je suis nouveau en PHP et c'est aussi mon premier journal dans le système de sorte qu'il serait excellent si vous les gars pourrait regarder par-dessus mon code et voir si vous pouvez repérer les failles de sécurité:
note: je suis à la désinfection de toutes les entrées utilisateur, bien qu'il n'est pas indiqué ici.
Inscrivez-Vous:
Étape 1: je prends le mot de passe que l'utilisateur a choisi et de le lancer à travers cette fonction:
encrypt($user_chosen_password, $salt);
function encrypt($plain_text, $salt) {
if(!$salt) {
$salt = uniqid(rand(0, 1000000));
}
return array(
'hash' => $salt.hash('sha512', $salt.$plain_text),
'salt' => $salt
);
}
Étape 2: je puis stocker le hash et le sel ($password['hash']
et $password['salt']
) dans la table des utilisateurs dans la base de données:
id | username | password | salt | unrelated info...
-----------------------------------------------------------
1 | bobby | 809a28377 | 809a28377f | ...
fd131e5934
180dc24e15
bbe5f8be77
371623ce36
4d5b851e46
Connecter:
Étape 1: - je prendre le nom d'utilisateur que l'utilisateur a entré et faire une rechercher sur la base de données pour voir si toutes les lignes sont renvoyées. Sur mon site n ° 2, les utilisateurs peuvent partager le même
nom d'utilisateur de sorte que le champ nom d'utilisateur a toujours une valeur unique. Si je reçois 1 ligne retournée, je prends le sel de cet utilisateur.
Étape 2: Puis-je exécuter l'utilisateur a entré le mot de passe par le biais de la fonction encrypt (comme précédemment posté ci-dessus), mais cette fois, j'ai également fournir le sel extrait de la base de données:
encrypt($user_entered_password, $salt);
Étape 3: j'ai maintenant le mot de passe correct pour le match contre dans cette variable: $password['hash']
. Alors j'ai donc une seconde de recherche sur la base de données pour voir si le
nom d'utilisateur entré et le mot de passe haché ensemble de retour d'une seule ligne. Si oui, alors l'utilisateur, les informations d'identification sont correctes.
Étape 4: afin de connecter l'utilisateur dans l'après leurs informations d'identification est passé, j'ai la génération aléatoire unique chaîne de hachage et c':
$random_string = uniqid(rand(0, 1000000));
$session_key = hash('sha512', $random_string);
Je puis insérez le $session_key
dans le active_sessions
table dans la base de données:
user_id | key
------------------------------------------------------------
1 | 431b5f80879068b304db1880d8b1fa7805c63dde5d3dd05a5b
Étape 5:
Je prends en clair chaîne unique généré à l'étape précédente ($random_string
) et définir la valeur d'un cookie que j'appelle active_session
:
setcookie('active_session', $random_string, time()+3600*48, '/');
Étape 6:
En haut de mon header.php
inclure il y a cette case:
if(isset($_COOKIE['active_session']) && !isset($_SESSION['userinfo'])) {
get_userinfo();
}
La get_userinfo()
fonction effectue une recherche sur le users
table dans la base de données et retourne un tableau associatif qui est stockée dans une session de userinfo
:
//d'abord cette fonction prend la valeur de la active_session cookie et les tables de hachage pour obtenir le session_key:
hash('sha512', $random_string);
//puis on fait une recherche sur le active_sessions
table pour voir si un enregistrement par cette key
existe, si si il va saisir la user_id
associés à cet enregistrement et l'utiliser pour faire une seconde de recherche sur la users
tableau pour obtenir le userinfo
:
$_SESSION['userinfo'] = array(
'user_id' => $row->user_id,
'username' => $row->username,
'dob' => $row->dob,
'country' => $row->country,
'city' => $row->city,
'zip' => $row->zip,
'email' => $row->email,
'avatar' => $row->avatar,
'account_status' => $row->account_status,
'timestamp' => $row->timestamp,
);
Si le userinfo
session existe, je sais que l'utilisateur est authentifié. S'il n'existe pas, mais la active_session
cookie existe alors que l'enregistrement
en haut de la header.php
fichier va créer la session.
La raison pour laquelle je suis à l'aide d'un cookie, et non des séances est seul à persister la connexion. Donc, si l'utilisateur ferme le navigateur, la session peut être disparu, mais l'
cookie existe toujours. Et depuis il n'y a qu'à cocher en haut de header.php
, la session sera recréé et l'utilisateur peut fonctionner en tant qu'utilisateur enregistré
en utilisateur normal.
Fermer La Session:
Étape 1: à la Fois la userinfo
session et la active_session
cookie ne sont pas définis.
Étape 2: de L'enregistrement associé de la active_sessions
table dans la base de données est supprimée.
Notes: Le seul problème que je vois (et peut-être il ya beaucoup d'autres), c'est que si l'utilisateur faux que active_session
cookie en créant eux-mêmes dans leur navigateur. Bien sûr, ils doivent définir en tant que témoin de la valeur d'une chaîne qui, après il est chiffré doit correspondre à un enregistrement dans la active_sessions
table d'où je vais récupérer le user_id
pour créer cette session. Je ne suis pas sûr de ce que sont les chances que cela est réaliste, pour un utilisateur (peut-être l'aide d'un programme automatisé) pour deviner une chaîne correctement laquelle ils ne savent pas sera alors sha512 chiffré et comparé à la chaîne dans l' active_sessions
table dans la base de données pour obtenir l'id de l'utilisateur pour construire cette session.
Désolé pour le gros essai, mais depuis c'est comme une partie essentielle de mon site et à cause de mon inexpérience, je voulais juste l'exécuter en plus de développeurs expérimentés pour s'assurer qu'il est réellement sans danger.
Donc, voyez-vous des trous de sécurité dans cette voie, et comment peut-il être amélioré?
- Je vais vous dire ce qui est évident - si vous n'êtes pas à l'aide de HTTPS pour transmettre le nom d'utilisateur/mot de passe, alors vous êtes très ouverts à toutes les attaques (Edit: d'autres que, personnellement, je ne peux pas voir les défauts. Mais ce n'est qu'une petite partie de l'image. Des exigences de complexité etc sont bonnes aussi, ainsi que de vérifier à travers tous les chemins de code)
- Johnstone vrai, mais je ne vais pas utiliser SSL pour ce site, au moins pour commencer.
- Alors les longueurs que vous allez sont inutiles, puisque dès le début, le mot de passe est transmis en clair. Si vous ne fait rien de tout cela, la première étape serait d'utiliser SSL/HTTPS. C'est la première étape..
- Si c'est le coût qui vous dérange, générer vos propres certificats auto-signés. Les utilisateurs seraient un avertissement (à juste titre), mais au moins leur mot de passe est crypté
- Le coût pour l'autorité de certification-signature de certificats n'est pas extravagant (environ 100 $et il y a quelques théoriquement libre de sources de trop). Beaucoup, beaucoup mieux avec https, aussi longtemps que vous comprenez ce que vous devez faire (y compris service de tous les contenus, y compris des images sur https). Voir aussi: security.stackexchange.com
- Mon plus gros souci n'est pas tellement que les comptes d'utilisateur sera piraté sur un seul utilisateur. Bien sûr, c'est très important, mais ce dont je suis le plus intéressé à ce sujet... Par exemple pour déterminer si un utilisateur peut modifier leur profil j'ai besoin pour s'assurer que leur nom d'utilisateur correspond au profil de l'utilisateur id utilisateur. Maintenant, si quelqu'un peut comprendre comment attraper les différents id utilisateur de l'active table des sessions et le définir comme leur propre, ils seront capables de dégrader des centaines d'autres profils d'utilisateurs.
- Vraiment un point mineur, toutes choses considérées, mais pensez à utiliser
mt_rand()
au lieu derand()
- cela signifie simplement que vous avez vraiment besoin de https. Voir mon commentaire sur Greg Hewgill du commentaire, ainsi que fixation de session, que vous devriez connaître (voir aussi Guide de Sécurité PHP: Sessions).
- Si vous utilisez
function encrypt($plain_text, $salt = null) {
, vous pouvez appeler la fonction avec un seul param commeencrypt($new_pass)
. - Notez que le hachage et de cryptage sont complètement différents: Un texte crypté peut être déchiffré qu'avec la clé correcte tout en un hachage de texte ne peut pas être inversée (one-way function).
- vous avez raison, je vais mettre à jour que le nom de la fonction.
- CA-signé certs peut être eu pour aussi peu que $9-10/an par cert. Personnellement, j'utilise ssls.com; j'ai obtenu mon certificat d'eux depuis 2011 (en arrière quand ils ont utilisé pour être cheapssls.com).
Vous devez vous connecter pour publier un commentaire.
Vous devez inclure une sorte de dépassement de délai ou de basculement pour prévenir contre les attaques en force. Il y a un certain nombre de façons de le faire, y compris de propriété intellectuelle basée sur le blocage des différentiels, les délais, etc. Aucun de ces éléments ne sera jamais arrêter un hacker, mais ils peuvent rendre beaucoup plus difficile.
Un autre point dont vous n'avez pas mentionné, alors je ne sais pas de votre plan) est l'échec des messages. Faire des messages de panne aussi vague que possible. Fournir un message d'erreur comme "ce nom d'utilisateur existe, mais les mots de passe ne correspondent pas' pourrait être utile à l'utilisateur final, mais elle tue la fonctionnalité de login. Vous avez juste converti une attaque par force brute qui devrait prendre
O(n^2)
temps deO(n)
+O(n)
. Au lieu d'essayer chaque permutation dans un arc-en-ciel de la table (par exemple), le pirate essaie juste de toutes les valeurs pour le nom d'utilisateur (avec un mot de passe) tout d'abord, jusqu'à ce que le message d'échec de changements. Ensuite, il sait un utilisateur valide, et vient à la force brute le mot de passe.Le long de ces lignes, vous devez également vous assurer que la même quantité de temps s'est écoulé lorsqu'un nom d'utilisateur existe et n'existe pas. Vous exécutez des processus supplémentaires lorsqu'un nom d'utilisateur existe réellement. En tant que tel, le temps de réponse serait plus lorsqu'un nom d'utilisateur existe vs quand ça ne marche pas. Un incroyablement habiles hacker pourrait de temps les demandes de page pour trouver un nom d'utilisateur valide.
De même, vous devriez assurez-vous que, en plus de l'expiration des cookies, vous expirent également la table des sessions.
Enfin, dans le
get_user_info()
appel, vous devez mettre fin à toutes les sessions ouvertes si il y a de multiples simultanées, connexions active. Assurez-vous de délai d'expiration des sessions après un nombre donné d'inactivité (30 minutes).Le long des lignes de ce que @Greg Hewgill mentionné, vous n'avez pas compris une des opérations suivantes:
Vous serveur est sûr, mais il n'a pas d'importance comment terriblement sûr de votre algorithme est si quelqu'un peut lire les données qui sont échangées (MITM). Assurez-vous que vous êtes seulement de communiquer via un protocole crypté.
Alors, comment obtenir le mot de passe à partir du navigateur vers le serveur? Vous n'avez pas mentionné la protection contre les man-in-the-middle attaques.
Ce code...
...est mauvais. Utilisez le nouveau mot de passe API et être fait avec elle. Sauf si vous êtes un expert, vous ne devriez pas essayer de concevoir votre propre système d'authentification. Ils sont extrêmement difficile d'obtenir le droit.
Juste laissez PHP poignée de gestion de session.
rand()
etmt_rand()
sont à la fois très précaire, des générateurs de nombres aléatoires.Il ressemble au code que vous avez créé n'est pas vérifiable par l'automatisation des tests unitaires et d'intégration. Cela le rend difficile à repérer toutes les erreurs qui pourraient être inclus dans votre mise en œuvre au fil du temps et lors de l'exécution dans un environnement de production.
Cela conduit en général à des problèmes de sécurité, car la sécurité d'une stricte et l'exécution correcte et saine de traitement des données n'est pas testé/vérifié.
(C'est juste un autre point de la liste, voir la réponse sur la façon de sécuriser la couche de transport, aussi vous n'avez pas spécifié comment vous protéger vos données de session à partir de la falsification.)
pw-hash
ethash
dans la db signifie? Est-ce un essai de choc?Relatives au mot de passe en php, vous ne devriez pas être en les chiffrant. Vous devriez hachage en utilisant l'
password_hash()
puis sur connexion, utilisezpassword_verify()
pour vérifier que le mot de passe via le formulaire html correspond au hash stocké dans la base de donnéesVous devez utiliser la fonction mt_rand() au lieu de rand()
Voici pourquoi: