Désinfection et validation des données avec WordPress

Une sécurité adéquate est essentielle à la sécurité de votre site ou de celui de votre thème ou des utilisateurs du plug-in. Une partie de cela implique une validation et une désinfection appropriées des données. Dans cet article, nous allons voir pourquoi c'est important, ce qu'il faut faire et quelles fonctions WordPress fournit pour vous aider.

Puisqu'il semble y avoir différentes interprétations de ce que signifient les termes «validation», «échappée» et «assainissement», je vais d'abord préciser ce que je veux dire par eux dans cet article:

  • Validation - Ce sont les contrôles qui sont exécutés pour assurer les données que vous avoir est ce que c'est devrait être. Par exemple, un courriel ressemble à une adresse électronique, une date est une date et un nombre est (ou est converti en) un entier
  • Assainissement / évasion - Ce sont les filtres qui sont appliqués aux données pour les rendre "sûres" dans un contexte spécifique. Par exemple, pour afficher le code HTML dans une zone de texte, il serait nécessaire de remplacer toutes les balises HTML par leurs équivalents d'entité.

Pourquoi la désinfection est-elle importante??

Lorsque les données sont incluses dans un certain contexte (par exemple dans un document HTML), elles peuvent être interprétées à tort comme un code pour cet environnement (par exemple un code HTML). Si ces données contiennent du code malveillant, utiliser ces données sans les assainir signifie que le code sera exécuté. Le code n'a même pas nécessairement besoin d'être malveillant pour provoquer des effets indésirables. La tâche de la désinfection est de s'assurer que tout code dans les données n'est pas interprété comme un code - sinon, vous pourriez vous retrouver comme l'école de Bobby Tables…

'Exploits of a Mom' - xkcd

Un exemple apparemment inoffensif pourrait être de pré-remplir un champ de recherche avec le terme actuellement interrogé, en utilisant le caractère non échappé. $ _GET ['s']:

 

Cela ouvre une vulnérabilité qui pourrait permettre l’injection de javascript, par exemple en incitant quelqu'un à visiter http://votresite.com?s= "/>. Le terme de recherche "saute" hors de l'attribut value et la partie suivante des données est interprétée comme un code et exécutée. Pour éviter cela, WordPress fournit get_search_query qui renvoie la requête de recherche désinfectée. Bien que ce soit un exemple "inoffensif", le script injecté pourrait être beaucoup plus malveillant et, au mieux, il "casserait" le formulaire si les termes de recherche contenaient des guillemets.

La manière dont ce code malveillant (ou non) a pu trouver son chemin sur votre site n’est pas la préoccupation ici, mais plutôt pour l’empêcher de s’exécuter. Nous ne faisons pas non plus d'hypothèses sur la nature de ce code non désiré, ou sur son intention - cela aurait pu être simplement une erreur de la part de l'utilisateur. Cela m'amène à la règle n ° 1…


Règle n ° 1: ne faire confiance à personne

C'est une maxime courante utilisée pour la désinfection des données, et c'est une bonne idée. L'idée est que vous ne devriez pas supposer que les données saisies par l'utilisateur sont en sécurité. Vous ne devez pas non plus présumer que les données extraites de la base de données sont sécurisées, même si vous les aviez sécurisées avant de les insérer dans celle-ci. En fait, si les données peuvent être considérées comme «sûres» n'a pas de sens sans contexte. Parfois, les mêmes données peuvent être utilisées dans plusieurs contextes sur la même page. Les titres, par exemple, peuvent contenir en toute sécurité des guillemets ou des guillemets doubles à l’intérieur des balises d’en-tête, mais poseront des problèmes s’ils sont utilisés (non échappés) dans un attribut title d’une balise de lien. Il est donc plutôt inutile de sécuriser les données lorsque vous les ajoutez à la base de données, car il est souvent impossible de sécuriser les données simultanément pour tous les contextes. (Bien sûr, il faut sécuriser l'ajout à la base de données - mais nous y reviendrons plus tard).

Même si vous avez l’intention d’utiliser ces données uniquement dans un contexte spécifique, par exemple un formulaire, il est toujours inutile de les purifier lors de l’écriture dans la base de données, car, conformément à la règle n ° 1, vous ne pouvez pas vous assurer qu’elle le sortir à nouveau.


Règle n ° 2: Valider à l'entrée, échapper à la sortie

Il s'agit de la maxime procédurale qui définit le moment où vous devez valider les données et quand vous les désinfectez. En d'autres termes, validez vos données (vérifiez que c'est bien ce qu'elles devraient être - et qu'elles sont «valides») dès que vous les recevez de l'utilisateur. Lorsque vous utilisez ces données, par exemple lorsque vous les exportez, vous devez les échapper (ou les désinfecter). La forme que prend cette désinfection dépend entièrement du contexte dans lequel vous l’utilisez..

Le meilleur conseil est d'exécuter cette opération "tardive": échappez vos données immédiatement avant de les utiliser ou de les afficher. De cette façon, vous pouvez être sûr que vos données ont été correctement épurées et vous n'avez pas besoin de vous rappeler si les données ont déjà été vérifiées..


Règle n ° 3: Faites confiance à WordPress

Vous pensez peut-être "OK, validez avant d'écrire dans la base de données et désinfectez-le lors de son utilisation. Mais n'ai-je pas besoin de m'assurer que les données peuvent être écrites sans danger dans la base de données?". En général, Oui. Lorsque vous ajoutez des données à une base de données ou utilisez simplement une entrée pour interagir avec une base de données, vous devez échapper aux données si celles-ci contiennent des commandes SQL. Mais cela m’amène à la règle n ° 3, qui va à l’encontre de la règle n ° 1: Trust WordPress.

Dans un article précédent, j’ai pris les entrées d’utilisateur (envoyées à partir d’un formulaire de recherche via AJAX) et les ai utilisées directement avec get_posts () pour renvoyer des publications correspondant à cette requête de recherche:

 $ posts = get_posts (array ('s' => $ _ REQUEST ['term']));

Un lecteur attentif a remarqué que je n'avais effectué aucune désinfection - et ils avaient raison. Mais je n'avais pas besoin de. Lorsque vous utilisez des fonctions de haut niveau telles que get_posts (), vous n'avez pas à vous soucier de la désinfection des données, car les requêtes de la base de données sont correctement traitées par les éléments internes de WordPress. Il en va tout autrement si vous utilisez une requête SQL directe - mais nous examinerons cela dans une section ultérieure. De même, des fonctions comme le titre(), the_permalink (), le contenu() etc. effectuer leur propre désinfection (pour le contexte approprié).


La validation des données

Lorsque vous recevez des données saisies par un utilisateur, il est important de: valider il. (L'API de paramètres, couverte dans cette série, vous permet de spécifier une fonction de rappel pour faire exactement cela). Les données non valides sont soit corrigées automatiquement, soit le processus est annulé et l'utilisateur est renvoyé au formulaire pour réessayer (éventuellement avec un message d'erreur approprié). La préoccupation ici n'est pas la sécurité mais la validité - si vous le faites bien, WordPress se chargera d'ajouter en toute sécurité les données à la base de données. Ce que vous entendez par "valide" appartient à vous - cela pourrait signifier une adresse électronique valide, un entier positif, un texte de longueur limitée ou l'une des nombreuses options spécifiées. Quel que soit le but recherché, WordPress propose de nombreuses fonctions pouvant vous aider..

Nombres

Lorsqu’on attend des données numériques, il est possible de vérifier si les données 'sont une forme de nombre', par exemple is_int ou is_float. Habituellement, il suffit de convertir les données sous forme numérique avec: intval ou floatval.

Si vous devez vous assurer que le nombre est rempli avec des zéros non significatifs, WordPress fournit la fonction zeroise (). Ce qui prend les paramètres suivants:

  • Nombre - le numéro de pad
  • Seuil - le nombre de chiffres auquel le numéro sera ajouté

Par exemple:

 echo zeroise (70,4); // Imprime 0070

Courriels

Pour vérifier la validité des courriels, WordPress a la is_email () une fonction. Cette fonction utilise des contrôles simples pour valider l'adresse. Par exemple, il vérifie qu'il contient le symbole "@", qu'il est plus long que 3 caractères, que le domaine ne contient que des caractères alphanumériques et des traits d'union, etc. De toute évidence, il ne vérifie pas que l'adresse électronique existe réellement. En supposant que l'adresse e-mail ait passé les contrôles, elle est renvoyée, sinon 'false' est renvoyé.

 $ email = is_email ('someone@e^ample.com'); // $ email est défini sur false. $ email = is_email ('[email protected]'); // $ email est défini sur '[email protected]'.

HTML

Souvent, vous souhaiterez peut-être n'autoriser que certains Balises HTML dans vos données - par exemple dans les commentaires postés sur votre site. WordPress fournit une famille de fonctions du formulaire wp_kses_ * (KSES Strips Evil Scripts). Ces fonctions suppriment (un sous-ensemble de) balises HTML et peuvent être utilisées pour garantir que les liens dans les données appartiennent à des protocoles spécifiés. Par exemple le wp_kses () La fonction accepte trois arguments:

  • contenu - (chaîne) Contenu à filtrer à travers kses
  • allowed_html - Un tableau où chaque clé est un élément HTML autorisé et la valeur est un tableau d'attributs autorisés pour cet élément
  • allowed_protocols - Optionnel. Protocole autorisé dans les liens (par exemple http, mailto, alimentation etc.)

wp_kses () est une fonction très flexible, vous permettant de supprimer les balises non désirées, ou simplement les attributs non désirés des balises. Par exemple, pour ne permettre que ou balises (mais n'autorise que l'attribut href):

 $ content = "Cliquez sur ici pour visiter  Wptuts+ "; echo wp_kses ($ content, array ('strong' => array (), 'a' => array ('href'))); // Imprime le code HTML" Cliquez ici pour visiter  Wptuts+ ": Cliquez ici pour visiter  Wptuts+ 

Bien sûr, spécifier chaque balise autorisée et chaque attribut autorisé peut être une tâche laborieuse. Donc, WordPress fournit d'autres fonctions qui vous permettent d'utiliser wp_kses avec des balises et des protocoles autorisés prédéfinis, notamment ceux utilisés pour la validation des publications et des commentaires:

  • wp_kses_post ()
  • wp_kses_data ()

Les fonctions ci-dessus permettent de s’assurer que le HTML reçu de l’utilisateur ne contient que des éléments de la liste blanche. Cela fait, nous voudrions également nous assurer que chaque balise est équilibrée, c'est-à-dire que chaque balise d'ouverture a sa balise de fermeture correspondante. Pour cela, nous pouvons utiliser balanceTags (). Cette fonction accepte deux arguments:

  • contenu - Contenu pour filtrer et équilibrer les balises de
  • équilibre des forces - Vrai ou faux, que ce soit pour forcer l'équilibrage des balises
 // Contenu avec fermeture manquante  tag $ content = "Cliquez sur ici pour visiter  wptuts + "; echo balanceTags ($ content, true), // Imprime le code HTML" Cliquez ici pour visiter  Wptuts+ "

Noms de fichiers

Si vous souhaitez créer un fichier dans l'un des répertoires de votre site Web, vous devez vous assurer que le nom du fichier est à la fois valide et légal. Vous voudriez également vous assurer que le nom de fichier est unique pour ce répertoire. Pour cela WordPress fournit:

  • sanitize_file_name ($ filename) - nettoie (ou valide) le nom de fichier en supprimant les caractères interdits dans les noms de fichiers sur certains systèmes d'exploitation ou nécessitant un échappement en ligne de commande. Remplace les espaces par des tirets et les tirets consécutifs par un seul tiret et supprime les points, les tirets et les traits de soulignement du début et de la fin du nom de fichier.
  • wp_unique_filename ($ dir, $ filename) - renvoie un unique (pour répertoire $ dir), nom de fichier désinfecté (il utilise sanitize_file_name).

Données des champs de texte

Lors de la réception de données entrées dans un champ de texte, vous voudrez probablement supprimer des espaces, des tabulations et des sauts de ligne supplémentaires, ainsi que supprimer toutes les balises. Pour cela WordPress fournit sanitize_text_field ().

Clés

WordPress fournit également sanitize_key. C'est une fonction très générique (et parfois utile). Cela garantit simplement que la variable renvoyée contient uniquement des caractères alphanumériques, des tirets et des traits de soulignement minuscules..


Désinfection des données

Alors que la validation vise à s’assurer que les données sont valides - la désinfection des données consiste à les rendre sûr. Certaines des fonctions de validation mentionnées ci-dessus peuvent être utiles pour garantir la sécurité des données. En général, cela ne suffit pas. Même des données «valides» peuvent être dangereuses dans certains contextes.


Règle n ° 4: La sécurisation des données relève du contexte

En termes simples, vous ne pouvez pas demander "Comment puis-je sécuriser ces données?". Au lieu de cela, vous devriez demander, "Comment puis-je sécuriser ces données pour les utiliser dans X".

Pour illustrer ce point, supposons que vous disposiez d'un widget avec une zone de texte dans laquelle vous souhaitez permettre à l'utilisateur de saisir du code HTML. Supposons qu'ils entrent ensuite:

  Bonjour le monde

Ceci est parfaitement valide et sûr, HTML. Cependant, lorsque vous cliquez sur Enregistrer, nous constatons que le texte est sorti de la zone de texte. Le code HTML n'est pas sûr en tant que valeur pour la zone de texte:

Ce qui peut être utilisé en toute sécurité dans un contexte ne l'est pas nécessairement dans un autre. Chaque fois que vous utilisez ou affichez des données, vous devez garder à l'esprit les formes de désinfection nécessaires pour sécuriser l'utilisation de ces données. C'est pourquoi WordPress fournit souvent plusieurs fonctions pour le même contenu, par exemple:

Toutes ces tâches effectuent la désinfection nécessaire pour un contexte particulier - et si vous les utilisez, vous devez être sûr d'utiliser le bon. Parfois, cependant, nous devrons procéder à notre propre nettoyage - souvent parce que nous avons des entrées personnalisées allant au-delà du titre, du lien permanent, du contenu, etc. que WordPress gère pour nous..

Échapper au HTML

Lorsque vous imprimez des variables sur la page, vous devez être conscient de la manière dont le navigateur les interprétera. Considérons l'exemple suivant:

 

Supposer $ title = . Plutôt que d'afficher le code HTML

En fait, si vous faites cela, vous devriez presque certainement utiliser wp_localize_script () - qui gère la désinfection pour vous. (Si quelqu'un peut penser à une raison pour laquelle vous pourriez avoir besoin d'utiliser la méthode ci-dessus à la place, j'aimerais l'entendre).

Cependant, pour sécuriser l’exemple ci-dessus, vous pouvez utiliser le esc_js une fonction:

 

Échapper à Textarea

Lors de l'affichage du contenu dans une zone de texte, esc_html n'est pas suffisant car il ne double pas les entités. Par exemple:

 texte audacieux'?> 

$ var imprimé dans la zone de texte apparaîtra comme:

 texte audacieux

Plutôt que d’encoder aussi le Et comme Et dans le Mots clés.

Pour cela WordPress fournit esc_textarea, qui est presque identique à esc_html, mais double-encode les entités. Essentiellement, c’est un peu plus qu’un emballage pour htmlspecialchars. Dans cet exemple:

 texte audacieux'?> 

Antispambot

L'affichage des adresses de messagerie sur votre site Web les laisse enclins à recueillir des courriers électroniques. Une méthode simple consiste à dissimuler l’adresse électronique. WordPress fournit antispambot, qui encode des parties aléatoires de l’adresse électronique dans leurs entités HTML (et leurs équivalents hexadécimaux si $ mailto = 1). À chaque chargement de page, l'encodage doit être différent et, si l'adresse renvoyée est correctement restituée dans le navigateur, elle doit apparaître sous forme de gobbledygook pour les spambots. La fonction accepte deux arguments:

  • email - l'adresse à brouiller
  • mailto - 1 ou 0 (1 si vous utilisez le protocole mailto dans une balise link)
 $ email = "[email protected]"; $ email = sanitize_email ($ email); echo '' .antispambot ($ email). ' ';

Chaîne de requête

Si vous souhaitez ajouter (ou supprimer) des variables à une chaîne de requête (ceci est très utile si vous souhaitez autoriser les utilisateurs à sélectionner une commande pour vos publications), le moyen le plus sûr et le plus simple consiste à utiliser add_query_arg et remove_query_arg. Ces fonctions gèrent toutes les échappements nécessaires pour les arguments et leurs valeurs à utiliser dans l'URL..

add_query_arg accepte deux arguments:

  • paramètres de requête - un tableau associatif de paramètres -> valeurs
  • url - l'URL pour ajouter les paramètres et leurs valeurs. Si omis, l'URL de la page en cours est utilisé

remove_query_arg accepte également deux arguments, le premier est un tableau de paramètres à supprimer, le second est comme ci-dessus.

 // Si nous sommes à l'adresse www.example.com/wp-admin/edit.php?post_type=book $ query_params = array ('page' => 'my-bage'); $ url = add_query_arg ($ query_params); // Définirait $ url sur: // www.example.com/wp-admin/edit.php?post_type=book&page=my-page

Validation et assainissement

Comme mentionné précédemment, la désinfection n'a pas de sens sans contexte - il est donc inutile de nettoyer les données lors de l'écriture dans la base de données. De toute façon, il est souvent nécessaire de stocker des données dans leur format brut, et dans tous les cas - la règle n ° 1 stipule que nous devons toujours procéder à une désinfection de la sortie..

En revanche, la validation des données doit être effectuée dès sa réception et avant son écriture dans la base de données. L'idée est que les données "non valides" doivent soit être corrigées automatiquement, soit être marquées avec les données, et que seules les données valides doivent être fournies à la base de données..

Cela dit, vous souhaiterez peut-être également effectuer une validation lorsque les données sont également affichées. En fait, parfois, la «validation» garantira également la sécurité des données. Mais la priorité ici est la sécurité et vous devriez éviter une validation excessive qui serait exécutée à chaque chargement de page (le wp_kses_ * les fonctions, par exemple, sont très coûteuses à exécuter).


Base de données échappée

Lorsque vous utilisez des fonctions telles que get_posts ou des cours tels que WP_Query et WP_User_Query, WordPress prend en charge la désinfection nécessaire pour interroger la base de données. Toutefois, lors de la récupération des données d'une table personnalisée ou de l'exécution d'une requête SQL directe sur la base de données, la désinfection appropriée vous appartient. WordPress, cependant, fournit une classe utile, le $ wpdb classe, qui aide à échapper aux requêtes SQL.

Considérons cette base 'SÉLECTIONNER'commande, où $ age et $ prenom sont des variables stockant un âge et un nom que nous interrogeons:

 SELECT * WHERE age = "$ age" AND prenom = '$ prenom'

Nous n’avons pas échappé à ces variables, de sorte que d’autres commandes pourraient éventuellement être injectées. Voici l’exemple de xkcd:

 $ age = 14; $ firstname = "Robert '; DROP TABLE Etudiants;"; $ sql = "SELECT * WHERE age =" $ age "AND prenom = '$ prenom';"; $ résultats = $ wpdb-> requête

S'exécutera en tant que commande (s):

 SELECT * WHERE age = "14" AND prenom = 'Robert'; DROP TABLE Etudiants; ';

Et supprimer notre tableau entier des étudiants.

Pour éviter cela, nous pouvons utiliser le $ wpdb-> prepare méthode. Ceci accepte deux paramètres:

  • La commande SQL en tant que chaîne, où les variables de chaîne sont remplacées par l'espace réservé % s et les nombres décimaux sont remplacés par l'espace réservé %ré et flotte par %F
  • Un tableau de valeurs pour les espaces réservés ci-dessus, dans l'ordre dans lequel elles apparaissent dans la requête

Dans cet exemple:

 $ age = 14; $ firstname = "Robert '; DROP TABLE Etudiants;"; $ sql = $ wpdb-> prepare ('SELECT * WHERE age =% d ET prenom =% s;', tableau ($ age, $ prenom)); $ résultats = $ wpdb-> get_results ($ sql);

La requête SQL échappée ($ sql dans cet exemple) peut ensuite être utilisé avec l’une des méthodes suivantes:

  • $ wpdb-> get_row ($ sql)
  • $ wpdb-> get_var ($ sql)
  • $ wpdb-> get_results ($ sql)
  • $ wpdb-> get_col ($ sql)
  • $ wpdb-> query ($ sql)

Insérer et mettre à jour des données

Pour insérer ou mettre à jour des données, WordPress simplifie encore plus la vie en fournissant le $ wpdb-> insert () et $ wpdb-> update () les méthodes.

le $ wpdb-> insert () La méthode accepte trois arguments:

  • Nom de la table - le nom de la table
  • Les données - tableau de données à insérer sous forme de paires colonne-> valeur
  • Les formats - tableau de formats pour les valeurs correspondantes ('% s','%ré' ou'%F')
 $ age = 14; $ firstname = "Robert '; DROP TABLE Etudiants;"; $ wpdb-> insert ('Students', array ('prenom' => $ prenom, 'age' => $ age), array ('% s', '% d'));

le $ wpdb-> update () La méthode accepte cinq arguments:

  • Nom de la table - le nom de la table
  • Les données - tableau de données à mettre à jour sous forme de paires colonne-> valeur
  • - tableau de données à faire correspondre sous forme de paires colonne-> valeur
  • Format de données - tableau de formats pour les valeurs de données correspondantes
  • Où Format - tableau de formats pour les valeurs 'where' correspondantes
 // Update Robert '; DROP TABLE étudiants; to Bobby $ oldname = "Robert '; DROP TABLE Etudiants;"; $ newname = "Bobby"; $ wpdb-> update ('Etudiants', tableau ('prénom' => $ nouveau nom), tableau ('prénom' => $ ancien nom), tableau ('% s'), tableau ('% s'));

Les deux $ wpdb-> insert () et le $ wpdb-> update () les méthodes effectuent toute la désinfection nécessaire pour écrire dans la base de données.

Comme des déclarations

Parce que le $ wpdb-> prepare méthode utilise % pour distinguer les remplaçants, il faut faire attention en utilisant le % Caractère générique dans les instructions SQL LIKE. Le Codex suggère de leur échapper avec une seconde %. Sinon, vous pouvez échapper au terme à rechercher avec like_escape puis ajoutez le joker % le cas échéant, avant de l'inclure dans la requête à l'aide de la méthode prepare. Par exemple:

 $ age = 14; $ firstname = "Robert '; DROP TABLE Etudiants;"; SELECT * WHERE age = $ age (prénom LIKE '% $ firstname%');

Serait en sécurité avec:

 $ age = 14; $ firstname = "Robert '; DROP TABLE Etudiants;"; SELECT * WHERE age = $ age AND (prénom LIKE '% $ firstname%'); $ query = $ wpdb-> prepare ('SELECT * WHERE age =% d AND (prénom LIKE% s);', tableau ($ age, '%'. like_escape ($ prenom). '%'));

Résumé

Ce n'est pas une liste exhaustive des fonctions disponibles pour la validation et la désinfection, mais elle devrait couvrir la grande majorité des cas d'utilisation. Beaucoup de ces fonctions (et d’autres) peuvent être trouvées dans /wp-includes/formatting.php et je vous recommande fortement de creuser dans le code principal et de jeter un coup d'œil à la façon dont le noyau WordPress effectue la validation et la purification des données.

Avez-vous trouvé cet article utile? Avez-vous d'autres suggestions sur les meilleures pratiques pour la validation et la désinfecti