Protégez les données scalaires des utilisateurs en PHP

Pour des raisons de sécurité, chaque développeur part du principe que les données envoyées par les utilisateurs d’une application web ne sont pas fiables.

C’est pour cette raison qu’il est en indispensable de contrôler toute donnée reçue. Les développeurs pensent bien à contrôler le format et le type des données reçues. Mais très souvent les contrôles des tableaux sont mal gérés. Quel est le véritable problème ? Comment s’en protéger ? Réponses.

Présentation du problème

Supposons le code PHP suivant :

$firstName = $_GET['first_name'];

Votre action attend une valeur scalaire. Mais supposons qu’un utilisateur envoie une requête HTTP avec un tableau (?first_name[]=value1&first_name[]=value2), votre action va recevoir un tableau (au lieu de recevoir une valeur scalaire). En fonction du déroulement de votre action, une exception PHP (ainsi qu’une erreur 500) peut être levée. Dans le cas de l’attente d’une valeur scalaire, le contrôle est très simple à mettre en place:

//Ce test est à mettre en place  en plus des autres tests (valeur non vide, longueur mini, maxi, ...)
if (!is_scalar($firstName)) {
    //Renvoyer une erreur à l'utilisateur
}

En revanche, dans le cas où notre action attend un tableau de valeurs scalaires, le piège est de réaliser le contrôle suivant :

$tags = $_GET['tags'];
if (!is_array($tags)) {
    //Renvoyer une erreur à l'utilisateur
}

En effet, si l’utilisateur envoie la requête HTTP ?tags[0]=value1&tags[1][0]=value2&tags[1][1]=value3 , le test précédent ne détectera aucune anomalie alors que les données reçues seront les suivantes:

Array
(
    [0] => value1
    [1] => Array
        (
            [0] => value2
            [1] => value3
        )
)

On obtient bien un tableau: Le test is_array retourne bien true. En revanche, ce test est incomplet: Les valeurs de ce tableau ne sont pas toutes scalaires, et en fonction du déroulement de votre action, une exception PHP (ainsi qu’une erreur 500) peut être levée.

Dans tous les exemples précédents, j’ai utilisé un simple code PHP. Mais le problème est aussi constaté avec l’utilisation de frameworks. Exemple avec Symfony avec l’utilisation de $request->query:

use Symfony\Component\HttpFoundation\Request;

public function index(Request $request)
{
    $tags = $request->query->get('tags');
    if (!is_array($tags)) {
        //Renvoyer une erreur à l'utilisateur
    }
    //Ici, même problème que exemple précédent
    //...
}

La réponse à ce problème? L’utilisation de ecommit/scalar-values

Présentation de ecommit/scalar-values

Vérifier que tous les enfants d’un tableau soient bien des valeurs scalaires est assez simple à faire à PHP. En revanche, dans le but d’éviter d’écrire ce test à chaque contrôle, j’ai créé pour cela une fonction dans la librairie ecommit/scalar-values (vous trouverez la procédure d’installation très simple à la racine du projet) :

use Ecommit\ScalarValues\ScalarValues;

$tags = $_GET['tags'];
if (!is_array($tags) || !ScalarValues::containsOnlyScalarValues($tags)) {
    //Renvoyer une erreur à l'utilisateur
}

Ou avec Symfony:

use Ecommit\ScalarValues\ScalarValues;
use Symfony\Component\HttpFoundation\Request;

public function index(Request $request)
{
    $tags = $request->query->get('tags');
    if (!is_array($tags) || !ScalarValues::containsOnlyScalarValues($tags)) {
        //Renvoyer une erreur à l'utilisateur
    }
    //...
}

Vous avez maintenant la certitude que toutes les valeurs de votre tableau sont bien des valeurs scalaires.

Petit bonus

Dans cette même librairie, j’ai ajouté aussi la fonction filterScalarValues qui vous retournera votre tableau nettoyé de toutes les valeurs non scalaires :

use Ecommit\ScalarValues\ScalarValues;

$tags = $_GET['tags'];
if (!is_array($tags)) {
    //Renvoyer une erreur à l'utilisateur
}
$tags = ScalarValues::filterScalarValues($tags);

Dans ce cas, si l’utilisateur envoie la requête HTTP ?tags[0]=value1&tags[1][0]=value2&tags[1][1]=value3 , la variable $tags aura en sortie la structure suivante :

Array
(
    [0] => value1
)

Petite librairie qui ne fait finalement pas grand-chose, mais qui permet de gagner du temps lors de l’écriture des contrôles.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Étiquettes :