LA CLOCHE

Il y en a qui ont lu cette news avant vous.
Abonnez-vous pour recevoir les derniers articles.
E-mail
Nom
Nom de famille
Aimeriez-vous lire The Bell
Pas de spam

Ceux qui ont étudié plus ou moins sérieusement PHP sachez qu'il existe un tableau global très utile dans PHP, qui est appelée $_SERVEUR. Et dans cet article, je voudrais analyser les clés les plus populaires et leurs valeurs dans ce tableau, car leur connaissance est simplement nécessaire même pour un débutant programmeur PHP.

Avant de procéder à au tableau global $_SERVER en PHP Je vais juste vous donner un petit indice. Il y a une fonctionnalité merveilleuse intégrée dans PHP, qui est appelée phpinfo(). Donnons tout de suite un exemple de son utilisation :

phpinfo();
?>

À la suite de l'exécution de ce script simple, vous verrez un énorme tableau avec divers Paramètres de l'interpréteur PHP, y compris, vers la fin, il y aura un tableau de valeurs tableau global $_SERVER. Il listera toutes les clés et toutes leurs valeurs correspondantes. Comment cela peut-il vous aider ? Et le fait que si vous avez besoin de telle ou telle valeur et que vous oubliez le nom de la clé, utilisez la fonction phpinfo() Vous pouvez toujours vous souvenir de son nom. En général, vous exécuterez ce script et vous me comprendrez immédiatement.

Passons maintenant aux plus populaires Clés du tableau $_SERVER:

  • HTTP_USER_AGENT- cette clé permet de connaître les caractéristiques du client. Dans la plupart des cas, il s'agit bien du navigateur, mais pas toujours. Et encore une fois, si le navigateur, alors lequel, vous pouvez en savoir plus dans cette variable.
  • HTTP_REFERER- contient le chemin absolu vers ce fichier ( Script PHP, Page HTML) à partir duquel vous êtes passé à ce script. En gros, d'où vient le client ?
  • SERVER_ADDR - adresse IP serveur.
  • REMOTE_ADDR - adresse IP client.
  • DOCUMENT_ROOT- chemin physique vers le répertoire racine du site. Cette option est définie via Fichier de configuration du serveur Apache.
  • SCRIPT_FILENAME- chemin physique vers le script appelé.
  • CHAÎNE DE REQUÊTE- une valeur très utile qui vous permet d'obtenir une chaîne avec une requête, puis vous pouvez analyser cette chaîne.
  • REQUEST_URI- une valeur encore plus utile qui contient non seulement la requête elle-même, mais également le chemin relatif vers le script appelé depuis la racine avec lui. Ceci est très souvent utilisé pour supprimer la duplication de index.php, c'est-à-dire lorsque nous avons un tel URL: "http://monsite.ru/index.php" et " http://monsite.ru/" mène à une page, et URL différent, donc, duplication, ce qui aura un effet néfaste sur l'optimisation des moteurs de recherche. Et ici avec l'aide REQUEST_URI on peut définir : index.php ou non le script a été appelé. Et nous pouvons rediriger avec index.php(s'il était présent REQUEST_URI) sur sans index.php. En conséquence, lors de l'envoi d'une telle demande : " http://monsite.ru/index.php?id=5", nous aurons une redirection vers URL: "http://monsite.ru/?id=5". C'est-à-dire que nous nous sommes débarrassés de la duplication en supprimant de URL cette index.php.
  • SCRIPT_NAME- chemin relatif vers le script appelé.

Ce sont peut-être tous des éléments Tableau global $_SERVER en PHP qui sont utilisés régulièrement. Ils doivent savoir et être capables d'utiliser si nécessaire.

Tableau superglobal $_SERVER

L'un des tableaux prédéfinis les plus importants est le tableau $_SERVER - l'interpréteur PHP y place les variables reçues du serveur. Sans ces variables, il est difficile d'organiser un support à part entière pour les applications Web. Les éléments les plus importants du tableau superglobal $_SERVER sont décrits ci-dessous.

Commentaire

Vous pouvez afficher la liste complète des éléments dans le tableau $_SERVER soit avec la fonction print_r(), qui imprime un vidage du tableau, soit avec la fonction phpinfo(), qui affiche des informations sur l'interpréteur PHP.

Élément $_SERVER["DOCUMENT_ROOT"]

L'élément $_SERVER["DOCUMENT_ROOT"] contient le chemin vers le répertoire racine du serveur ; si le script est exécuté dans un hôte virtuel, cet élément spécifie le chemin vers le répertoire racine de l'hôte virtuel. Ceux. dans le fichier de configuration httpd.conf, l'hôte virtuel a une directive DocumentRoot définie sur "D:/main", l'élément $_SERVER["DOCUMENT_ROOT"] contiendra la valeur "D:main".

Élément $_SERVER["HTTP_ACCEPT"]

L'élément $_SERVER["HTTP_ACCEPT"] décrit la préférence du client concernant le type de document. Le contenu de cet élément est extrait de l'en-tête HTTP Accept envoyé du client au serveur. Le contenu de cet en-tête pourrait ressembler à ceci

image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/msword, */*

L'en-tête Accept vous permet de spécifier le type de média que le client préfère recevoir en réponse à sa demande. Cet en-tête vous permet d'indiquer au serveur que la réponse est limitée à un petit ensemble de types préférés.

Le symbole * est utilisé pour regrouper les types dans une ligne média. Par exemple, le symbole */* spécifie l'utilisation de tous les types et la notation type/* spécifie l'utilisation de tous les sous-types du type de type sélectionné.

Commentaire

Les types de médias sont séparés les uns des autres par des virgules.

Chaque ligne de support est également caractérisée par un ensemble supplémentaire de paramètres. L'un d'eux est le soi-disant coefficient de préférence relative q, qui prend des valeurs de 0 à 1, respectivement, des types les moins préférés aux plus préférés. L'utilisation de plusieurs paramètres q permet au client d'indiquer au serveur le degré relatif de préférence pour un type de média donné.

Commentaire

Le paramètre q prend par défaut la valeur 1. Il est également séparé du type de média par un point-virgule.

Exemple d'en-tête Accept :

Accepter : audio/* ; q=0,2, audio/de base

Dans cet en-tête, le premier type est audio/*, qui regroupe tous les documents musicaux et se caractérise par un coefficient de préférence de 0,2. Un type audio/de base séparé par des virgules est spécifié, pour lequel le coefficient de préférence n'est pas spécifié et prend une valeur par défaut de un. Citant RFC2616, cet en-tête peut être interprété comme suit : « Je préfère le type audio/de base, mais je peux également envoyer des documents de tout autre type audio, si disponible, après avoir réduit le coefficient de préférence de plus de 80 % ».

L'exemple pourrait être plus complexe.

Accepter : texte/brut ; q=0.5, texte/html,
texte/x-dvi ; q=0.8, texte/x-c

Commentaire

Notez que l'élément $_SERVER["HTTP_ACCEPT"] contient exactement les mêmes informations, mais sans l'en-tête Accept initial.

Cet en-tête est interprété comme suit : Les types de document text/html et text/x-c sont préférés, mais s'ils ne sont pas disponibles, alors le client faisant cette requête préférera text/x-dvi, et sinon, il pourra accepter le type texte/ clair.

Élément $_SERVER["HTTP_ACCEPT_LANGUAGE"]

L'élément $_SERVER["HTTP_ACCEPT_LANGUAGE"] décrit les préférences linguistiques du client. Ces informations sont extraites de l'en-tête HTTP Accept-Language envoyé par le client au serveur. L'exemple suivant peut être donné :

Accepter-Langue : ru, en ; q=0,7

Ce qui peut être interprété comme suit : le client préfère la langue russe, mais si elle n'est pas disponible, il s'engage à accepter des documents en anglais. L'élément $_SERVER["HTTP_ACCEPT_LANGUAGE"] contiendra exactement les mêmes informations, mais sans l'en-tête Accept-Language :

ru, fr ; q=0,7

Le contenu de l'élément $_SERVER["HTTP_ACCEPT_LANGUAGE"] peut être utilisé pour déterminer la nationalité des visiteurs. Cependant, les résultats seront approximatifs, car de nombreux utilisateurs utilisent des navigateurs anglais, qui informeront le serveur que le visiteur ne préfère qu'une seule langue - l'anglais.

Élément $_SERVER["HTTP_HOST"]

L'élément $_SERVER["HTTP_HOST"] contient le nom du serveur, qui est généralement le même que le nom de domaine du site hébergé sur le serveur. Généralement, le nom spécifié dans ce paramètre est le même que $_SERVER["SERVER_NAME"]. Le paramètre contient uniquement le nom de domaine sans le nom de protocole (http://), c'est-à-dire

www.sofftime.ru

Élément $_SERVER["HTTP_REFERER"]

L'élément $_SERVER["HTTP_REFERER"] contient l'adresse de la page à partir de laquelle le visiteur est venu sur cette page. La transition doit se faire via un lien. Créons deux pages index.php et page.php.

page index.php

écho "Lien vers la page PHP
"
;
écho .
$_SERVER["HTTP_REFERER"]
?>

La page page.php aura un contenu similaire, mais le lien pointera vers la page index.php.

Page page.php

écho "Lien vers la page PHP
"
;
écho "Le contenu de $_SERVER["HTTP_REFERER"] est ".
$_SERVER["HTTP_REFERER"]
?>

Lors du passage d'une page à une autre, l'adresse de la page à partir de laquelle la transition a été effectuée sera affichée sous le lien.

Élément $_SERVER["HTTP_USER_AGENT"]

L'élément $_SERVER["HTTP_USER_AGENT"] contient des informations sur le type et la version du navigateur et du système d'exploitation du visiteur.

Voici le contenu typique de cette ligne : "Mozilla/4.0 (compatible ; MSIE 6.0 ; Windows NT 5.1)". La présence de la sous-chaîne "MSIE 6.0" indique que le visiteur consulte la page à l'aide d'Internet Explorer version 6.0. La chaîne "Windows NT 5.1" indique que le système d'exploitation est Windows XP.

Commentaire

Pour Windows 2000, l'élément $_SERVER["HTTP_USER_AGENT"] ressemble à ceci : "Mozilla/4.0 (compatible ; MSIE 5.01 ; Windows NT 5.0)")", tandis que pour Windows XP, il ressemble à "Mozilla/4.0 (compatible ; MSIE 6.0) ; Windows NT 5.1)".

Si le visiteur utilise le navigateur Opera, le contenu de $_SERVER["HTTP_USER_AGENT"] peut ressembler à ceci : "Mozilla/4.0 (compatible ; MSIE 5.0 ; Windows 98) Opera 6.04 ". La sous-chaîne "MSIE 6.0" est également présente ici, indiquant que le navigateur Opera est compatible avec le navigateur Internet Explorer et utilise les mêmes DLL Windows. Par conséquent, lors de l'analyse de la chaîne renvoyée par le navigateur, gardez à l'esprit qu'Internet Explorer fait référence à une chaîne contenant la sous-chaîne "MSIE 6.0" et ne contenant pas la sous-chaîne "Opera". De plus, à partir de cette ligne, nous pouvons conclure que l'utilisateur utilise le système d'exploitation Windows 98.

Commentaire

L'agent utilisateur du navigateur Firefox pourrait ressembler à ceci Mozilla/5.0 (Windows ; U ; Windows NT 5.1 ; en-US ; rv:1.8) Gecko/20051111 Firefox/1.5.

Lors de l'utilisation du navigateur Netscape, le contenu de l'élément $_SERVER["HTTP_USER_AGENT"] peut ressembler à ceci : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" . Ce navigateur peut être identifié par la présence de la sous-chaîne "Netscape". De plus, vous pouvez découvrir que le visiteur accède à Internet à l'aide d'un système d'exploitation Linux avec un noyau optimisé pour Pentium IV dans l'interface graphique X-Window. Ce mécanisme est utile pour collecter des informations statistiques qui permettent aux concepteurs d'optimiser les pages pour les navigateurs les plus courants.

Élément $_SERVER["REMOTE_ADDR"]

L'élément $_SERVER["REMOTE_ADDR"] contient l'adresse IP du client. Lors du test sur une machine locale, cette adresse sera 127.0.0.1. Cependant, lors des tests sur le réseau, la variable renverra l'adresse IP du client ou du dernier serveur proxy par lequel le client est arrivé au serveur. Si le client utilise un serveur proxy, vous pouvez connaître son adresse IP à l'aide de la variable d'environnement HTTP_X_FORWARDED_FOR dont la valeur peut être obtenue à l'aide de la fonction getenv().

Commentaire

Les serveurs proxy sont des serveurs intermédiaires spéciaux qui fournissent un type de service particulier : compression du trafic, encodage des données, adaptation aux appareils mobiles, etc. Parmi les nombreux serveurs proxy, il existe des serveurs proxy dits anonymes qui permettent de masquer la véritable adresse IP du client ; ces serveurs ne renvoient pas la variable d'environnement HTTP_X_FORWARDED_FOR.

Récupération de la variable d'environnement HTTP_X_FORWARDED_FOR

echo getenv(HTTP_X_FORWARDED_FOR );
?>

Élément $_SERVER["SCRIPT_FILENAME"]

L'élément $_SERVER["SCRIPT_FILENAME"] contient le chemin absolu vers le fichier à partir de la racine du lecteur. Ainsi, si le serveur fonctionne sous le système d'exploitation Windows, un tel chemin pourrait ressembler à ceci : "d:main estindex.php", c'est-à-dire le chemin est spécifié à partir du disque, dans un système d'exploitation de type UNIX, le chemin est spécifié à partir du répertoire racine /, par exemple "/var/share/www/test/index.php".

Élément $_SERVER["SERVER_NAME"]

L'élément $_SERVER["SERVER_NAME"] contient le nom du serveur, qui correspond généralement au nom de domaine du site hébergé sur celui-ci. Par exemple,

www.softtime.ru

Le contenu de l'élément $_SERVER["SERVER_NAME"] est souvent le même que le contenu de l'élément $_SERVER["HTTP_HOST"]. Outre le nom du serveur, le tableau superglobal $_SERVER vous permet de connaître un certain nombre de paramètres du serveur, tels que l'adresse IP du serveur, le port d'écoute, le serveur Web installé et la version du protocole HTTP. Ces informations sont placées respectivement dans les éléments $_SERVER["SERVER_ADDR"], $_SERVER["SERVER_PORT"], $_SERVER["SERVER_SOFTWARE"] et $_SERVER["SERVER_PROTOCOL"]. Vous trouverez ci-dessous un exemple utilisant ces éléments.

Utilisation des éléments du tableau $_SERVER

echo "Nom du serveur - " . $_SERVER["SERVER_NAME"]. "
" ;
écho "Adresse IP du serveur - ". $_SERVER["SERVER_ADDR"]. "
" ;
echo "Port du serveur - " . $_SERVER["SERVER_PORT"]. "
" ;
echo "Serveur Web - " . $_SERVER["SERVER_LOGICIEL"]. "
" ;
écho « Version du protocole HTTP - ». $_SERVER["SERVER_PROTOCOL"]. "
" ;
?>

Élément $_SERVER["REQUEST_METHOD"]

L'élément $_SERVER["REQUEST_METHOD"] contient la méthode de requête utilisée pour appeler le script : GET ou POST.

Le composant permet d'afficher le formulaire d'autorisation. Il est généralement utilisé dans le modèle de conception de site Web. Le composant est standard et est inclus dans le kit de distribution du module. Dans l'éditeur visuel, le composant est situé le long du chemin : Service > Utilisateur.

Dans l'éditeur visuel, le composant est situé le long du chemin : Outils système > Utilisateur > Formulaire d'autorisation.

Exemple d'appel de composant system.auth.form

Description des paramètres

Mécanisme de récupération de mot de passe (pour référence)

Si l'utilisateur a demandé la récupération du mot de passe, la récupération se produit selon le mécanisme suivant :

  1. L'utilisateur clique sur Mot de passe oublié? dans le formulaire d'autorisation.
  2. Une chaîne aléatoire de 32 caractères est générée, étant donné un secret connu uniquement du serveur.
  3. Le résultat est écrit dans la base de données et envoyé par courrier. Voir le lien : http://site.ru/bitrix/admin/index.php?change_password=yes&lang=ru&USER_CHECKWORD=3farde09fay52547f11c68bf17d95760&USER_LOGIN=market, où:
    • http://site.ru/bitrix/admin/index.php - chemin vers la page d'autorisation ou de changement de mot de passe ;
    • change_password=yes - action de changement de mot de passe ;
    • lang=ru identifiant de langue ;
    • USER_CHECKWORD=- vérifier la chaîne pour changer le mot de passe, 32 caractères. La chaîne utilise des caractères. disponible pour md5 : .

      Lors de la modification du mot de passe dans l'invite de chaîne de vérification, entrez uniquement la chaîne de vérification, sans USER_CHECKWORD= !

    • &USER_LOGIN=market - une indication pour quel utilisateur le mot de passe est modifié.
  4. Lors de la comparaison de la chaîne de contrôle du formulaire avec ce qui est écrit dans la base de données, le délai d'expiration spécifié dans le groupe de sécurité est pris en compte.

Noter. Il est recommandé d'utiliser CAPTCHA dans le formulaire de récupération de mot de passe - champ Utilisez CAPTCHA lors de la récupération du mot de passe dans les paramètres du module principal.


Bitrix, 2001-2019, 1C-Bitrix, 2019

Reg.ru : domaines et hébergement

Le plus grand registraire et fournisseur d'hébergement en Russie.

Plus de 2 millions de noms de domaine en service.

Promotion, mail pour le domaine, solutions pour les entreprises.

Plus de 700 000 clients à travers le monde ont déjà fait leur choix.

*Passez la souris pour interrompre le défilement.

Retour en avant

Création d'un système d'enregistrement d'utilisateur simple en PHP et MySQL

La création d'un système d'enregistrement représente beaucoup de travail. Vous devez écrire du code qui valide les adresses e-mail, envoie un e-mail de confirmation, valide d'autres champs de formulaire, et bien plus encore.

Et même après avoir écrit tout cela, les utilisateurs hésiteront à s'inscrire, car. cela demande un certain effort de leur part.

Dans ce didacticiel, nous allons créer un système de connexion très simple qui ne nécessite ni ne stocke aucun mot de passe ! Le résultat sera facile à modifier et à ajouter à un site PHP déjà existant. Vous voulez savoir comment ça marche ? Lire ci-dessous.



Voici comment notre système super simple fonctionnerait :

Nous combinerons le formulaire d'autorisation et l'enregistrement. Ce formulaire aura un champ pour saisir une adresse e-mail et un bouton d'inscription ;
- Lorsque vous remplissez le champ avec une adresse e-mail, en cliquant sur le bouton d'inscription, un enregistrement concernant un nouvel utilisateur sera créé, mais uniquement si l'adresse e-mail saisie n'a pas été trouvée dans la base de données.

Après cela, un jeu de caractères unique aléatoire (jeton) est créé, qui est envoyé au courrier spécifié par l'utilisateur sous la forme d'un lien qui sera pertinent pendant 10 minutes ;
- En cliquant sur le lien, l'utilisateur accède à notre site Web. Le système détermine la présence du jeton et autorise l'utilisateur ;

Les avantages de cette approche :

Pas besoin de stocker des mots de passe et de valider des champs ;
- Pas besoin de récupération de mot de passe, de questions secrètes, etc. ;
- A partir du moment où l'utilisateur s'est enregistré/connecté, vous pouvez toujours être sûr que cet utilisateur sera dans votre zone d'accès (que l'adresse e-mail est vraie) ;
- Processus d'inscription incroyablement simple ;

Défauts:

Sécurité du compte utilisateur. Si quelqu'un a accès au courrier de l'utilisateur, il peut se connecter.
- Le courrier électronique n'est pas sécurisé et peut être intercepté. Gardez à l'esprit que cette question est également pertinente dans le cas où le mot de passe a été oublié et doit être restauré, ou dans tout système d'autorisation qui n'utilise pas HTTPS pour le transfert de données (login / mot de passe) ;
- Tant que vous configurez le serveur de messagerie selon vos besoins, il est possible que les messages contenant des liens d'autorisation se retrouvent dans les spams ;

En comparant les avantages et les inconvénients de notre système, nous pouvons dire que le système a une grande facilité d'utilisation (commodité maximale pour l'utilisateur final) et, en même temps, a un indicateur de sécurité faible.

Il est donc proposé de l'utiliser pour les inscriptions sur les forums et services qui ne fonctionnent pas avec des informations importantes.

Comment utiliser ce système

Dans le cas où vous avez juste besoin d'utiliser le système pour autoriser les utilisateurs sur votre site, et que vous ne souhaitez pas démonter cette leçon, voici ce que vous devez faire :

Vous devez télécharger les fichiers sources joints à la leçon
- Retrouver le fichier dans l'archive tables.sql Importez-le dans votre base de données en utilisant l'option d'importation dans phpMyAdmin. Autre méthode : ouvrez ce fichier avec un éditeur de texte, copiez la requête SQL et exécutez-la ;
- Ouvert inclut/main.php et renseignez les paramètres de connexion à votre base de données (précisez l'utilisateur et le mot de passe de connexion à la base de données, ainsi que l'hébergeur et le nom de la base de données). Dans le même fichier, vous devez également spécifier une adresse e-mail qui sera utilisée comme adresse d'origine pour les messages envoyés par le système. Certains hôtes bloqueront les e-mails sortants jusqu'à ce que le formulaire affiche une adresse e-mail réelle créée à partir du panneau de configuration de l'hôte, alors entrez la véritable adresse ;
- Télécharger tous les fichiers index.php, protégé.php et les actifs et inclut les dossiers via FTP vers votre hébergeur ;
- Ajoutez le code ci-dessous à chaque page PHP où vous souhaitez afficher un formulaire d'autorisation ;

Require_once "inclut/main.php" ; $user = nouvel utilisateur(); if(!$user->loggedIn())( redirect("index.php"); )
- Prêt!

Pour ceux qui sont intéressés par le fonctionnement de tout cela, lisez ci-dessous !

La première étape consiste à écrire le code HTM pour le formulaire d'autorisation. Ce code se trouve dans le fichier index.php. Ce fichier contient également le code PHP qui gère les données du formulaire et d'autres fonctionnalités utiles du système d'autorisation. Vous pouvez en savoir plus à ce sujet dans la section de révision du code PHP ci-dessous.

index.php

Tutoriel : Système d'enregistrement super simple avec PHP et MySQL

Connexion ou Inscription

Entrez votre adresse e-mail ci-dessus et nous vous enverrons
votre lien de connexion.

Dans la section head (entre les balises et) J'ai inclus les principaux styles (ils ne sont pas analysés dans ce tutoriel, vous pouvez donc les voir vous-même. Le dossier assets/css/style.css). Avant la balise fermante J'ai inclus la bibliothèque jQuery et le fichier script.js, que nous allons écrire et analyser ci-dessous.


Javascript

jQuery garde une trace de l'état du bouton "Inscription/Connexion" avec une fonction e.preventDefault() et envoie des requêtes AJAX. En fonction de la réponse du serveur, affiche un message particulier et détermine d'autres actions /

actifs/js/script.js

$(function())( var form = $("#login-register"); form.on("submit", function(e)( if(form.is(".loading, .loggedIn"))( return false ; ) var email = form.find("input").val(), messageHolder = form.find("span"); e.preventDefault(); $.post(this.action, (email: email), fonction (m)( if(m.error)( form.addClass("error"); messageHolder.text(m.message); ) else( form.removeClass("error").addClass("loggedIn"); messageHolder. text(m.message); ) )); )); $(document).ajaxStart(function())( form.addClass("loading"); )); $(document).ajaxComplete(function())( form. removeClass("loading"); )); ));

a été ajouté au formulaire pour afficher l'état actuel de la requête AJAX (cela a été rendu possible grâce aux méthodes ajaxStart()) et ajaxComplet(), que vous pouvez trouver vers la fin du fichier).

Cette classe affiche un fichier gif animé en rotation (comme s'il nous indiquait que la demande était en cours de traitement), et agit également comme un indicateur pour empêcher le formulaire d'être resoumis (lorsque le bouton d'enregistrement a déjà été cliqué une fois). Classer .connecté- ceci est un indicateur différent - défini lorsque l'e-mail a été envoyé. Cet indicateur bloque instantanément toute action ultérieure sur le formulaire.

Schéma de base de données

Notre système d'enregistrement incroyablement simple utilise 2 tables MySQL (le code SQL est dans le fichier tables.sql). Le premier stocke des données sur les comptes d'utilisateurs. Le second stocke des informations sur le nombre de tentatives de connexion.


Schéma de table utilisateur.

Le système n'utilise pas de mots de passe, comme le montre le schéma. Vous pouvez y voir la colonne jeton avec des jetons adjacents à la colonne token_validity. Le jeton est défini dès que l'utilisateur se connecte au système, configure son e-mail pour envoyer un message (un peu plus à ce sujet dans le bloc suivant). Colonne token_validity définit l'heure 10 minutes plus tard, après quoi le jeton n'est plus valide.


Schéma de table qui comptabilise le nombre de tentatives d'autorisation.

Dans les deux tables, l'adresse IP est stockée sous une forme traitée, à l'aide de la fonction ip2long, dans un champ entier.

Nous pouvons maintenant écrire du code PHP. La fonctionnalité principale du système est attribuée à la classe utilisateur.classe.php que vous pouvez voir ci-dessous.

Cette classe utilise activement idorm (docs), ces bibliothèques sont les outils minimum nécessaires pour travailler avec des bases de données. Il gère l'accès à la base de données, la génération et la validation des jetons. Il s'agit d'une interface simple qui permet de connecter facilement un système d'enregistrement à votre site s'il utilise PHP.

utilisateur.classe.php

Class User( // Private ORM case private $orm; /** * Trouver un utilisateur par token. Seuls les tokens valides sont pris en considération. Le token n'est généré que pendant 10 minutes à partir du moment où il a été créé * @param string $token . C'est celui que vous recherchez token * @return User. Renvoie la valeur de la fonction User */ public static function findByToken($token)( // trouve le token dans la base de données et s'assure que l'horodatage correct est défini $ result = ORM::for_table("reg_users") ->where ("token", $token) ->where_raw("token_validity > NOW()") ->find_one(); if(!$result)( return false; ) return new User($result); ) /** * Autoriser ou enregistrer un utilisateur * @param string $email.Adresse e-mail de l'utilisateur * @return User */ public static function loginOrRegister($email)( // Si un tel utilisateur existe déjà, renvoie la valeur de la fonction Utilisateur à partir de l'adresse e-mail spécifiée stockée dans la base de données if(User::exists($email))( return new User($email); ) // Sinon, crée un nouvel utilisateur tel dans la base de données et renvoie la valeur de la fonction User::create à partir de l'e-mail spécifié return User::create($email); ) /** * Créer un nouvel utilisateur et l'enregistrer dans la base de données * @param string $email. Adresse e-mail de l'utilisateur * @return User */ private static function create($email)( // Enregistre un nouvel utilisateur et renvoie le résultat de la fonction User à partir de ces valeurs $result = ORM::for_table("reg_users")- >create(); $result->email = $email; $result->save(); return new User($result); ) /** * Vérifie si un tel utilisateur existe dans la base de données et renvoie la valeur booléenne de variable * @param chaîne $email. Adresse e-mail de l'utilisateur * @return boolean */ public static function exists($email)( // L'utilisateur existe-t-il dans la base de données ? $result = ORM::for_table("reg_users") ->where("email", $email ) ->count(); return $result == 1; ) /** * Créer un nouvel objet utilisateur * @param instance $param ORM , id, email ou 0 * @return User */ public function __construct($param = null) ( if($param instanceof ORM)( // Vérification ORM réussie $this->orm = $param; ) else if(is_string($param))( // Vérification des e-mails réussie $this->orm = ORM :: for_table ("reg_users") ->where("email", $param) ->find_one(); ) else( $id = 0; if(is_numeric($param))( // l'identifiant de l'utilisateur reçoit la valeur de $ param variable $id = $param; ) else if(isset($_SESSION["loginid"]))( // Sinon voir session $id = $_SESSION["loginid"]; ) $this->orm = ORM :: for_table( "reg_users") ->where("id", $id) ->find_one(); ) ) /** * Génère un nouveau jeton d'autorisation SHA1, écrit à la base de données et renvoie sa valeur * @return string */ public function generateToken()() // Génère un jeton pour un utilisateur autorisé et l'enregistre dans la base de données $token = sha1($this->email.time().rand (0, 1000000 )); // Stocke le jeton dans la base de données // Et le marque comme valide uniquement pour les 10 prochaines minutes $this->orm->set("token", $token); $this->orm->set_expr("token_validity", "ADDTIME(NOW(),"0:10")"); $this->orm->save(); retourne $token ; ) /** * Autoriser l'utilisateur * @return void */ public function login()() // Marquer l'utilisateur comme connecté $_SESSION["loginid"] = $this->orm->id; // Mettre à jour la valeur du champ de base de données last_login $this->orm->set_expr("last_login", "NOW()"); $this->orm->save(); ) /** * Détruit la session et déconnecte l'utilisateur * @return void */ public function logout ()( $_SESSION = array(); unset($_SESSION); ) /** * Vérifie si l'utilisateur est connecté * @return boolean */ public function logIn())( return isset($ this->orm->id) && $_SESSION["loginid"] == $this->orm->id; ) /** * Vérifie si l'utilisateur est un administrateur * @return boolean */ public function isAdmin() ( return $this->rank() = = "administrator"; ) /** * Recherche le type d'utilisateur, peut être administrateur ou normal * @return string */ fonction publique rank())( if($this->orm- >rank == 1)( return "administrator"; ) return "regular"; ) /** * Une méthode qui vous permet d'obtenir des informations privées * en tant que propriétés de l'objet User * @param string $key Le nom de la propriété en cours d'accès * @return mixed */ public function __get($key)( if(isset($this->orm->$key) )( retourne $this->orm->$key ; ) renvoie null ; ) )

Les jetons sont générés à l'aide de l'algorithme SHA1 et stockés dans la base de données. J'utilise les fonctions de temps de MySQL pour définir une limite d'expiration de jeton de 10 minutes.

Lorsque le jeton passe la procédure de validation, nous indiquons directement au gestionnaire que nous ne considérons que les jetons qui n'ont pas encore expiré, stockés dans la colonne token_validity.

Veuillez noter que j'utilise la méthode magique __obtenir docs à la fin du fichier pour intercepter l'accès aux propriétés de l'objet User.

Grâce à cela, il devient possible d'accéder aux informations stockées dans la base de données, grâce aux propriétés $user->email, $user->token etc. Dans l'extrait de code suivant, prenons un exemple d'utilisation de ces classes.


Page protégée

Un autre fichier qui stocke les fonctionnalités utiles et nécessaires est le fichier fonctions.php. Il existe plusieurs soi-disant assistants ici - des fonctions d'assistance qui vous permettent de créer un code plus propre et plus lisible dans d'autres fichiers.

fonctions.php

Function send_email($from, $to, $subject, $message)( // Helper qui envoie un email $headers = "MIME-Version: 1.0" . "\r\n"; $headers .= "Content-type: text /plain; charset=utf-8" . "\r\n"; $headers .= "From: ".$from . "\r\n"; return mail($to, $subject, $message, $headers ); ) function get_page_url()() // Récupère l'URL du fichier PHP $url = "http".(empty($_SERVER["HTTPS"])?"":"s")."://".$_SERVER [ "SERVER_NAME"] ; if(isset($_SERVER["REQUEST_URI"]) && $_SERVER["REQUEST_URI"] != "")( $url.= $_SERVER["REQUEST_URI"]; ) else( $url. = $_SERVER["PATH_INFO"] ; ) return $url ; ) function rate_limit($ip, $limit_hour = 20, $limit_10_min = 10)( // Nombre de tentatives de connexion au cours de la dernière heure à cette adresse IP $count_hour = ORM : :for_table("reg_login_attempt") ->where("ip", sprintf("%u", ip2long($ip))) ->where_raw("ts > SUBTIME(NOW(),"1:00")") ->count(); // Nombre de tentatives de connexion au cours des 10 dernières minutes à cette adresse IP $count_10_min = ORM::for_table("reg_login_attempt") ->where("ip", sprint f("%u", ip2long($ip))) ->where_raw("ts > SUBTIME(NOW(),"0:10")") ->count(); if($count_hour > $limit_hour || $count_10_min > $limit_10_min)( throw new Exception("Trop de tentatives de connexion!"); ) ) function rate_limit_tick($ip, $email)( // Créer une nouvelle entrée dans le tableau compter le nombre de tentatives de connexion $login_attempt = ORM::for_table("reg_login_attempt")->create(); $login_attempt->email = $email; $login_attempt->ip = sprintf("%u", ip2long($ip) ); $login_attempt->save(); ) function redirect($url)( header("Location: $url"); exit; )

Les fonctions rate_limit et rate_limit_tick surveiller le nombre de tentatives d'autorisation pour la période écoulée depuis la première tentative. La tentative de connexion est enregistrée dans la base de données dans la colonne reg_login_attempt. Ces fonctions sont appelées lorsque les données du formulaire sont traitées et soumises, comme vous pouvez le voir dans l'extrait de code suivant.

Le code ci-dessous est extrait du fichier index.php et il gère la soumission du formulaire. Il renvoie une réponse JSON qui est à son tour traitée par jQuery dans un fichier actifs/js/script.js dont nous avons déjà parlé précédemment.

index.php

Try( if(!empty($_POST) && isset($_SERVER["HTTP_X_REQUESTED_WITH"]))( // Sort un header JSON header("Content-type: application/json"); // Cette adresse e-mail est-elle valide si (!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL))( throw new Exception("Please enter a valid email."); ) // Check. Est-ce que le utilisateur autorisé à se connecter, a-t-il dépassé le nombre de connexions autorisées ? (fichier functions.php pour plus d'informations) rate_limit($_SERVER["REMOTE_ADDR"]); // Enregistrer cette tentative de connexion rate_limit_tick($_SERVER["REMOTE_ADDR"] , $ _POST["email"]); // Envoie un e-mail à l'utilisateur $message = ""; $email = $_POST["email"]; $subject = "Votre lien de connexion"; if(!User :: exists($email) )( $subject = "Merci pour votre inscription!"; $message = "Merci pour votre inscription sur notre site !\n\n"; ) // Tentative d'autorisation ou d'enregistrement d'un utilisateur $user = Utilisateur ::loginOrRegister($_POST[ "email"]); $message.= "Vous pouvez vous connecter depuis cette URL :\n" ; $message.= get_page_url()."?tkn=".$user->generateToken()."\n\n" ; $message.= "Le lien expirera automatiquement après 10 minutes."; $result = send_email($fromEmail, $_POST["email"], $subject, $message); if(!$result)( throw new Exception("Une erreur s'est produite lors de l'envoi de votre e-mail. Veuillez réessayer."); ) die(json_encode(array("message" => "Merci ! Nous avons envoyé un lien dans votre boîte de réception. Vérifiez également votre dossier spam.")))); ) ) catch(Exception $e)( die(json_encode(array("error"=>1, "message" => $e->getMessage( ) ))); )

Après une autorisation/inscription réussie, le code ci-dessus enverra à l'utilisateur un lien d'autorisation. Le jeton devient disponible car il est passé en variable dans le lien généré par la méthode $_GET avec marqueur tkn

index.php

If(isset($_GET["tkn"]))( // Ce jeton est-il valide pour l'autorisation ? $user = User::findByToken($_GET["tkn"]); if($user)( // Oui , est. Rediriger vers la page protégée $user->login(); redirect("protected.php"); ) // Non, le jeton n'est pas valide. Rediriger vers la page avec le formulaire de connexion/inscription redirect("index. php "); )

$user->login()

créera les variables nécessaires à la session, de sorte que l'utilisateur, tout en consultant les pages suivantes du site, restera connecté en permanence.

De même, le traitement de la fonction de sortie du système est organisé.

index.php

If(isset($_GET["logout"]))( $user = new User(); if($user->loggedIn())( $user->logout(); ) redirect("index.php") ; )

A la fin du code, j'ai de nouveau redirigé vers index.php, donc le paramètre ?déconnexion=1 passé par URL n'est pas obligatoire.

Notre dossier index.php nécessite des protection - nous ne voulons pas que les personnes qui se sont déjà connectées au système voient à nouveau le formulaire d'inscription. A ces fins, nous utilisons la méthode $user->connecté().

index.php

$user = nouvel utilisateur(); if($user->loggedIn())( redirect("protected.php"); )

Enfin, voici un morceau de code qui vous permet de protéger les pages de votre site et de le rendre disponible uniquement après autorisation.

protégé.php

// Pour sécuriser chaque page de votre site, incluez un fichier // main.php et créez un nouvel objet User. C'est aussi simple que ça ! require_once "inclut/main.php" ; $user = nouvel utilisateur(); if(!$user->loggedIn())( redirect("index.php"); )

Après cette vérification, vous pouvez être sûr que l'utilisateur a été autorisé avec succès. Vous pouvez également accéder aux informations stockées dans la base de données à l'aide des propriétés de l'objet $utilisateur. Pour afficher l'adresse e-mail et l'état de l'utilisateur, utilisez ce code :

echo "Votre email : ".$user->email; echo "Votre classement : ".$user->rank();

Méthode rang() est utilisé ici car les nombres sont généralement stockés dans la base de données (0 pour un utilisateur normal, 1 pour un administrateur) et nous devons convertir ces données dans les statuts auxquels elles appartiennent, ce à quoi cette méthode nous aide.

Pour faire d'un utilisateur normal un administrateur, modifiez simplement l'entrée de l'utilisateur via phpMyAdmin (ou tout autre programme qui vous permet de gérer des bases de données). Le statut d'administrateur ne donne aucun privilège, dans cet exemple, la page affichera que vous êtes un administrateur - et c'est tout.

Mais que faire avec cela - cela reste à votre discrétion, vous pouvez écrire et composer vous-même du code qui définit certains privilèges et opportunités pour les administrateurs.

Avaient fini!

Avec cette forme incroyablement super quasi simple, nous avons terminé ! Vous pouvez l'utiliser dans vos sites PHP, c'est assez simple. Vous pouvez également le modifier vous-même et le faire comme vous le souhaitez.

Le matériel a été préparé par Denis Malyshok spécifiquement pour le site du site

PS Vous souhaitez aller plus loin dans la maîtrise de PHP et de la POO ? Jetez un coup d'œil à des didacticiels premium sur divers aspects de la création de sites Web, y compris la programmation PHP, ainsi qu'à un cours gratuit sur la création de votre système PHP CMS à partir de zéro à l'aide de la POO :

Vous avez aimé le matériel et vous voulez remercier?
Partagez simplement avec vos amis et collègues!


Aujourd'hui, nous allons nous intéresser à l'exploitation d'une vulnérabilité critique 1day dans le populaire CMS Joomla, qui a explosé sur Internet fin octobre. Nous parlerons des vulnérabilités avec des chiffres CVE-2016-8869, CVE-2016-8870 et CVE-2016-9081. Tous trois proviennent du même morceau de code qui a langui dans les entrailles du framework pendant cinq longues années, attendant dans les coulisses pour se libérer et apporter avec lui le chaos, les sites piratés et les larmes des utilisateurs innocents de ce Joomla. Seuls les développeurs les plus vaillants et les plus courageux, dont les yeux sont rouges à cause de la lumière des moniteurs et les claviers jonchés de miettes de pain, ont pu défier les mauvais esprits déchaînés et poser leur tête sur l'autel des correctifs.

ATTENTION

Toutes les informations sont fournies à titre informatif uniquement. Ni les éditeurs ni l'auteur ne sont responsables de tout dommage éventuel causé par le contenu de cet article.

Comment tout a commencé

Le 6 octobre 2016, Demis Palma a créé un sujet sur Stack Exchange, dans lequel il demandait : pourquoi, en fait, dans la version 3.6 de Joomla, il existe deux méthodes pour enregistrer les utilisateurs avec le même nom register() ? Le premier est dans le contrôleur UsersControllerRegistration et le second dans UsersControllerUser . Damis voulait savoir si la méthode UsersControllerUser::register() est utilisée quelque part, ou s'il s'agit simplement d'un anachronisme évolutif hérité de l'ancienne logique. Il était préoccupé par le fait que même si cette méthode n'est utilisée par aucune vue, elle peut toujours être appelée avec une requête générée. À quoi j'ai reçu une réponse du développeur sous le pseudo itoctopus, qui a confirmé que le problème existe vraiment. Et envoyé un rapport aux développeurs Joomla.

D'autres événements se sont développés plus rapidement. Le 18 octobre, les développeurs de Joomla acceptent un rapport de Damis, qui à ce moment-là avait rédigé un PoC qui permet l'enregistrement des utilisateurs. Il a publié une note sur son site Web, où il a parlé en termes généraux du problème qu'il a trouvé et de ses réflexions à ce sujet. Le même jour, une nouvelle version de Joomla 3.6.3 est publiée, qui contient toujours du code vulnérable.

Après cela, Davide Tampellini tourne le bogue à l'état d'enregistrer non pas un simple utilisateur, mais un administrateur. Et déjà le 21 octobre, un nouveau cas arrive à l'équipe de sécurité de Joomla. Il parle déjà d'escalade de privilèges. Le même jour, une annonce apparaît sur le site Web Joomla indiquant que le mardi 25 octobre, la prochaine version portant le numéro de série 3.6.3 sera publiée, ce qui corrige une vulnérabilité critique dans le cœur du système.

Le 25 octobre, l'équipe Joomla Security Strike trouve le dernier problème créé par un morceau de code découvert par Damis. Ensuite, un commit du 21 octobre avec le nom discret Prepare 3.6.4 Stable Release est poussé vers la branche principale du référentiel officiel Joomla, ce qui corrige le bogue malheureux.

Après cette sortie, de nombreuses personnes intéressées rejoignent la cabale des développeurs - ils commencent à tourner la vulnérabilité et à préparer des sploits.

Le 27 octobre, le chercheur Harry Roberts télécharge un exploit prêt à l'emploi sur le référentiel Xiphos Research qui peut télécharger un fichier PHP sur un serveur avec un CMS vulnérable.

Détails

Eh bien, la préhistoire est terminée, passons au plus intéressant - l'analyse de la vulnérabilité. En tant que version expérimentale, j'ai installé Joomla 3.6.3, donc tous les numéros de ligne seront pertinents pour cette version. Et tous les chemins vers les fichiers que vous voyez ensuite seront indiqués par rapport à la racine du CMS installé.

Grâce à la découverte de Damis Palma, nous savons qu'il existe deux méthodes qui effectuent l'enregistrement des utilisateurs dans le système. Le premier est utilisé par le CMS et se trouve dans le fichier /components/com_users/controllers/registration.php:108. Le second (celui que nous devons appeler) réside dans /components/com_users/controllers/user.php:293 . Regardons-le de plus près.

286 : /** 287 : * Méthode pour enregistrer un utilisateur. 288: * 289: * @return boolean 290: * 291: * @since 1.6 292: */ 293: public function register() 294: ( 295: JSession::checkToken("post") or jexit(JText::_ ("JINVALID_TOKEN")); ... 300 : // Récupère les données du formulaire. 301 : $data = $this->input->post->get("user", array(), "array"); . .. 315 : $return = $model->validate($form, $data); 316 : 317 : // Vérifie les erreurs 318 : if ($return === false) 319 : ( ... 345 : / / Terminez l'enregistrement.346 : $return = $model->register($data);

Ici, je n'ai laissé que des lignes intéressantes. La version complète de la méthode vulnérable peut être consultée dans le référentiel Joomla.

Voyons ce qui se passe lors d'un enregistrement d'utilisateur normal : quelles données sont envoyées et comment elles sont traitées. Si l'enregistrement de l'utilisateur est activé dans les paramètres, le formulaire se trouve à l'adresse http://joomla.local/index.php/component/users/?view=registration .


Une demande d'enregistrement d'utilisateur légitime ressemble à la capture d'écran suivante.


Le composant com_users est chargé de travailler avec les utilisateurs. Faites attention au paramètre de tâche dans la requête. Il a le format $controller.$method . Regardons la structure du fichier.

Noms de script dans le dossier contrôleurs correspondent aux noms des contrôleurs appelés. Puisque notre requête a maintenant $controller="registration" , le fichier sera appelé inscription.php et sa méthode register().

Attention, la question est : comment transférer le traitement de l'enregistrement à un endroit vulnérable du code ? Vous l'avez probablement déjà deviné. Les noms des méthodes vulnérables et réelles sont les mêmes (registre), il suffit donc de changer le nom du contrôleur appelé. Et où est le contrôleur vulnérable ? C'est vrai, dans le dossier utilisateur.php. Il s'avère que $controller = "user" . En mettant tout cela ensemble, nous obtenons task = user.register . Maintenant, la demande d'enregistrement est traitée par la méthode dont nous avons besoin.


La deuxième chose que nous devons faire est d'envoyer les données dans le bon format. Tout est simple ici. Register() légitime attend de nous un tableau appelé jform , dans lequel nous transmettons des données pour l'enregistrement - nom, identifiant, mot de passe, courrier (voir la capture d'écran avec la demande).

  • /components/com_users/controllers/registration.php: 124 : // Récupère les données de l'utilisateur. 125 : $requestData = $this->input->post->get("jform", array(), "array");

Notre enfant reçoit ces données d'un tableau nommé user .

  • /components/com_users/controllers/user.php: 301 : // Récupère les données du formulaire. 302 : $data = $this->input->post->get("user", array(), "array");

Par conséquent, nous changeons les noms de tous les paramètres de la requête de jfrom en user .

Notre troisième étape consiste à trouver un jeton CSRF valide, car sans lui, il n'y aura pas d'enregistrement.

  • /components/com_users/controllers/user.php: 296: JSession::checkToken("post") or jexit(JText::_("JINVALID_TOKEN"));

Cela ressemble à un hachage MD5, et vous pouvez le prendre, par exemple, à partir du formulaire d'autorisation sur le site /index.php/component/users/?view=login .


Vous pouvez maintenant créer des utilisateurs via la méthode souhaitée. Si tout a fonctionné, alors félicitations - vous venez d'exploiter une vulnérabilité CVE-2016-8870"Vérification d'autorisation manquante pour l'enregistrement de nouveaux utilisateurs."

Voici à quoi cela ressemble dans la méthode "de travail" register() du contrôleur UsersControllerRegistration :

  • /components/com_users/controllers/registration.php: 113 : // Si l'enregistrement est désactivé - Rediriger vers la page de connexion. 114 : if (JComponentHelper::getParams("com_users")->get("allowUserRegistration") == 0) 115 : ( 116: $this->setRedirect(JRoute::_("index.php?option=com_users&view= login", faux)); 117 : 118 : renvoie faux ; 119 : )

Et donc chez les vulnérables :

  • /components/com_users/controllers/user.php :

Ouais, pas moyen.

Pour comprendre le deuxième problème, beaucoup plus sérieux, envoyons la requête que nous avons formée et voyons comment elle est exécutée dans différentes parties du code. Voici la pièce chargée de valider les données soumises par l'utilisateur dans la méthode de travail :

Suite disponible uniquement pour les membres

Option 1. Rejoignez la communauté "site" pour lire tous les documents sur le site

L'adhésion à la communauté pendant la période spécifiée vous donnera accès à TOUS les matériaux Hacker, augmentera votre remise cumulée personnelle et vous permettra d'accumuler une note professionnelle Xakep Score !

LA CLOCHE

Il y en a qui ont lu cette news avant vous.
Abonnez-vous pour recevoir les derniers articles.
E-mail
Nom
Nom de famille
Aimeriez-vous lire The Bell
Pas de spam