web-dev-qa-db-fra.com

Quelle est la meilleure façon de purifier les entrées utilisateur en PHP?

Quelle est la meilleure façon de désinfecter les entrées des utilisateurs?

Ce sont des choses que je fais lorsque les utilisateurs soumettent des données:

  1. substr si plus de valeurs limitées sont trouvées.
  2. htmlspecialchars() + ent_quotes + UTF-8
  3. str_replace '<' '>' entrée utilisateurs

Que faut-il faire de plus?

31
user2615947

La "désinfection" est un terme inutile et trompeur. Il y a deux animaux différents ici:

  1. Sortie s'échappant. Il s'agit d'un problème d'étape de sortie. Lorsque vous prenez des chaînes variables et les injectez dans une chaîne plus grande qui a une syntaxe environnante, vous devez traiter la chaîne injectée pour la rendre conforme aux exigences de cette syntaxe. En quoi consiste exactement ce traitement dépend du contexte: si vous mettez du texte en HTML, vous devez HTML-échapper ce texte au moment de faire le HTML. Si vous placez du texte dans des requêtes SQL, vous devez échapper SQL du texte au moment de créer la requête. (*)

  2. Validation des entrées. Il s'agit d'un problème de l'étape d'entrée, en s'assurant que l'entrée utilisateur est dans les valeurs possibles acceptées pour un élément de données. Il s'agit principalement de règles métier, à considérer champ par champ, bien qu'il existe certains types de validation qu'il est logique de faire pour presque tous les champs de saisie (en recherchant principalement les caractères de contrôle).

La validation des entrées a un impact sur la sécurité, car elle peut atténuer les dommages lorsque vous avez fait une erreur lors de l'échappement de votre sortie. Mais il ne suffit pas de s'appuyer sur la validation des entrées comme seule mesure de gestion de texte, car vous devrez toujours autoriser l'utilisateur à utiliser certains caractères spéciaux dans la syntaxe certains ou l'autre. Vous allez vouloir avoir une page Web sur fish & chips et un client de votre base de données appelé O'Reilly.

La "désinfection" confond ces deux concepts et vous encourage à les aborder au même stade, ce qui ne peut jamais fonctionner de manière cohérente. Un anti-modèle courant consiste à échapper HTML à toutes vos entrées. Mais vous ne savez pas si chaque élément d'entrée va être sorti en HTML (et seulement sorti en HTML) à cette phase de traitement d'entrée. Si tu fais ça:

  • vous vous retrouvez avec du matériel encodé en HTML dans la base de données, qui ne peut pas être découpé et traité sans que les références d'entité ne gênent;

  • si vous avez besoin de créer un contenu à partir de ces données qui n'est pas HTML, comme envoyer un e-mail ou écrire du CSV, vous avez du texte déformé laid;

  • si vous obtenez du contenu dans votre base de données à partir d'une autre source, il se peut qu'il ne soit pas échappé au HTML et que sa sortie directement sur la page vous donne toujours des vulnérabilités XSS.

La "désinfection" en tant que concept devrait être détruite par le feu, puis noyée, coupée en petits morceaux et détruite par un peu plus de feu.

(*: dans les deux cas, il est plus judicieux de choisir une méthode qui effectue le traitement implicitement pour vous afin de ne pas vous tromper: utilisez un langage de modèle HTML qui échappe à la sortie par défaut, et une couche d'accès aux données qui utilise des requêtes paramétrées ou mappage relationnel-objet. De même pour d'autres types d'échappement: préférez un sérialiseur XML conforme aux normes à l'échappement XML manuel, utilisez un sérialiseur JSON standard pour transmettre des données à JavaScript, etc.)

substr si plus de valeurs limitées sont trouvées.

Voulez-vous dire tronquer des chaînes d'entrée trop longues? C'est OK comme forme de validation d'entrée où vos règles métier ont une raison valable de limiter la longueur d'une entrée. Mais vous préférerez peut-être renvoyer une erreur à l'utilisateur si vous avez une chaîne d'entrée trop longue, car en fonction du champ, il peut ne pas être approprié de supprimer discrètement les données.

htmlspecialchars () + ent_quotes + UTF-8

C'est la sortie qui s'échappe. Faites-le sur les valeurs au moment où vous les déposez en HTML, pas sur l'entrée. Si vous utilisez un modèle PHP modèle, vous pouvez vous définir un raccourci pour le taper plus rapidement, par exemple:

function h($s) {
    echo htmlspecialchars($s, ENT_QUOTES, 'utf-8')l
}
...

<p>Hello, <?php h($user['name']); ?>!</p>

str_replace <> entrée des utilisateurs

Pourquoi? Si vous échappez correctement au HTML, ces caractères sont parfaitement corrects, et à moins que vos règles métier ne disent le contraire, ils peuvent être tout à fait valides à inclure dans un champ, tout comme les deux caractères sont valides pour moi de taper dans cette zone de commentaire pour SO.

Bien sûr, vous voudrez peut-être les interdire dans la validation des entrées pour des champs spécifiques - vous ne voudriez pas les avoir dans un numéro de téléphone.

49
bobince

J'utilise les filtres OWASP PHP. Ils sont vraiment simples à utiliser et efficaces.

https://www.owasp.org/index.php/OWASP_PHP_Filters

Le code source est très lisible. Il y a beaucoup de leçons douloureuses là-dedans.

11
mgjk

Comme il s'agit d'un problème il y a plusieurs années, certaines choses changent et les liens externes se replient généralement car les sites ne maintiennent pas ou ne traitent pas les liens qui peuvent exister dans d'autres sites.

Donc, pour continuer, PHP a évolué un peu et beaucoup de gens demandent des informations sur la désinfection des entrées mais pour l'instant, l'utilisation de filter_var est mince sur le sol, bien que pas parfait, c'est de ma lecture, coffre-fort binaire.

Vous obtenez donc une adresse e-mail, sauf si vous n'utilisez pas HTML5 alors que vous devriez l'utiliser en conjonction avec PHP filter_var, votre site sera plus sécurisé que quelqu'un qui écrit une routine pour nettoyer une entrée qui n'utilise pas les entrées HTML5. Écrire du code pour une compatibilité ascendante pour les navigateurs non conformes HTML5 est complètement inutile et une perte de temps et de ressources.

L'autre problème de sécurité est que les valeurs de $ _GET et $ _POST sont volatiles et peuvent changer ou être changées en externe des bonnes données aux mauvaises données, donc toute routine de nettoyage qui les utilise et leur renvoie des entrées nettoyées est juste mûre pour trouble ... $ _REQUEST array est plus sûr, il une fois défini dans votre tableau sécurisé, il ne peut pas être modifié, alors remplissez votre tableau sécurisé en prenant les entrées et filtrez-les dans le tableau sécurisé.

Comment je désinfecte les entrées est quelque chose comme ce qui suit ...

$someSafeArray = array(
        "thefield"=>FILTER_SANITIZE_STRING,
        "theNumberfield"=>FILTER_SANITIZE_NUMBER,
        "theEmailfield"=>FILTER_SANITIZE_EMAIL
        );
foreach( $someSafeArray as $fld=>&$val)
    $val = filter_var( trim( $_REQUEST[$fld] ), $val );

Ainsi, cela renverra tous les champs (à partir des clés) et les entrées filtrées sont ensuite mises dans les valeurs de ces clés dans le tableau sécurisé.

Cela signifie que j'utilise les clés d'une liste blanche (tableau) pour prendre UNIQUEMENT les entrées que je désigne comme étant des champs valides. J'ai vu trop de gens proposer des processeurs de formulaires "dynamiques" qui acceptent N'IMPORTE QUELLE entrée, NON !!! Vous ne devez accepter que les flux de données que votre code/formulaire est conçu pour gérer.

SALER votre page avec une valeur que votre formulaire de réception peut recalculer le hachage correct pour vérifier que votre formulaire a été émis par le serveur, champs VIDE, j'inclus au moins un firld vierge qui est en lecture seule, caché comme les champs de hachage mais l'intention est de déterminer si le formulaire est poussé ou non, un bot remplira tous les champs avec des données pour essayer d'ouvrir la page.

Donc appâter votre page avec quelques champs factices comme ...

<input name="userlogin" type="hidden" value="" readonly />
<input name="empty" type="hidden" value="" readonly />

si le formulaire est arrivé sur votre serveur avec quelque chose dans le champ de valeur de l'une ou l'autre entrée, vous pouvez aussi bien arrêter tout traitement de formulaire et enregistrer l'adresse IP de l'utilisateur et les bloquer car ils sont soit un bot, soit un pirate.

L'injection n'est pas seulement un problème SQL, c'est un problème de page PHP, donc faites attention aux champs que vous acceptez, à ce que salt et bait votre formulaire avec et exploiter une liste blanche.

ARRÊTEZ D'UTILISER les GET pour passer les paramètres de contrôle, UTILISEZ un cookie de session car cela réduit les entrées dans le script, si j'utilise une URL de type GET, ce n'est que pour une tactique subversive et permet de surveiller les utilisateurs qui piquent des variables dans l'URL et d'autres choses pour essayer de pirater.

J'utilise un processus comme celui-ci depuis avant l'introduction de la fonction filter_var, je salais des pages sans avoir besoin d'une base de données pour valider les pages entrantes et c'était quelque chose qui m'était dit à plusieurs reprises par de soi-disant professionnels n'était pas possible, eh bien le la seule chose que je dois dire, c'est que "c'est si vous êtes capable de penser en dehors de la plaque de la chaudière. (boîte)" et assez simple pour contrecarrer les tentatives de piratage, sécurisez vos pages de formulaire.

4
Mark Giblin

Je ne voudrais personnellement jamais str_replace sur < et >, juste balises de bande , caractères spéciaux html , encodage des entités html , mysql_real_escape_string etc sur l'entrée utilisateur.

Ce dont vous devez tenir compte est de savoir comment les données vont être représentées?

  • Va-t-il être sorti sur le front-end?
  • Va-t-il dans la base de données?
  • Va-t-il être utilisé en Javascript sur le front-end?
  • Que diriez-vous de l'inclusion de fichiers?

Si cela va dans le front-end, alors vous devez l'htmlentities et strip_tags imo, de cette façon, vous pouvez être sûr qu'ils n'essaient pas d'exécuter du code indésirable.

En outre, la suppression des barres obliques est une considération assez importante, j'ai récemment attrapé un XSS dans le WP plugin SEO Platinum dans lequel vous pouvez exécuter du code javascript via le paramètre $ _GET ['s'] en encodant tout en code hexadécimal échappé (\\ x41 = A).

Si vous entrez des données dans la base de données, jetez un œil aux requêtes préparées par PDO ainsi qu'aux mysql_real_escape_string . Cela devrait sécuriser assez bien les entrées de votre base de données.

Si vous utilisez une entrée utilisateur pour demander des fichiers, assurez-vous qu'ils ne sont pas sensibles aux attaques Poison Null Byte et à mon avis, supprimez toujours toutes les barres obliques sur les fichiers inclus, pour vous assurer qu'ils ne peuvent pas accéder à l'emplacement voulu. Je recommanderais également de désactiver allow_url_include/allow_url_fopen dans votre fichier php.ini.

J'espère que ça aide!

0
DarkMantis