Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Se protéger des $_get

  1. ###raw>post.musername###
    Membre régulier
    Salut à tous,
    je récupère les infos passées dans l'url d'un site par $_SERVER
    et je les mets dans une bd voir ce qui se passe.

    Assez fréquement il y a ce style:

    16:07:11|/index.php?p=accueil.php

    16:07:13|/index.php?p=accueil.php&gyGS=4073%20AND%201%3D1%20UNION%20ALL%20SELECT%201%2CNULL%2C%27%3Cscript%3Ealert

    %28%22XSS%22%29%3C%2Fscript%3E%27%2Ctable_name%20FROM%20information_schema.tables%20WHERE%202%3E1--%2F%2A%2A%2F%3B

    %20EXEC%20xp_cmdshell%28%27cat%20..%2F..%2F..%2Fetc%2Fpasswd%27%29%23

    16:07:14|/index.php?p=accueil.php%22%28%27.%2C%2C..%2C%2C

    16:07:15|/index.php?p=accueil.php%27ePVCmH%3C%27%22%3ELamIUJ

    Donc des information_schema, des passwd et autre cmdshell

    J'ai déjà fait un truc comme:
    - "Si l'url contient les mots delete, update, drop etc... "
    > session_destroy et localStorage.clear();sessionStorage.clear();

    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $get=strtolower(strip_tags($_SERVER['QUERY_STRING']));
    if (strstr($get,'delete')||strstr($get,'select')||strstr($get,'update')||strstr($get,'insert')||strstr($get,'drop')||strstr($get,'create')||strstr($get,'execute')) 
    {
        echo 'Désolé, j\'ai piscine';
        session_destroy();
        echo '<script type="text/javascript">localStorage.clear();sessionStorage.clear();</script>';
    }

    Aussi, ca fait beaucoup de mot à tester
    (à chaque rechargement de page).

    En $_GET je passe uniquement
    le nom de la page p et des fois un id
    ex:
    Code html :Sélectionner tout -Visualiser dans une fenêtre à part
    index.php?p=accueil.php&&id=xx

    Pour info, dans index.php il y a
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    if (!@include($_GET['p'])) {include('home.php');}


    Est-ce qu'on pourrait limiter cette recherche fastidieuse de:
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    if (strstr($get,'delete')||strstr($get,'select') ... ||strstr($get,'execute')) 
    {...}
    en ne cherchant que les $_GET valides
    avec des caractères génériques lorsqu'il y a un &&id=xx?

    Sinon, lister les GET
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if (isset($_GET)) {
      foreach ($_GET as $key => $value_get) {
     	// si c'est un pas un get maison 'p' ou 'id'
    	if($key != 'p' || $key != 'id') 
    	{echo 'Merci, bonsoir !';}
      }}

    Et pour les POST, comment pourrait-on les repérer ?

    Merci cavo789 pour aesecuremais c'est un peu chaud à utiliser. https://www.aesecure.com/logiciel/telecharger

    La bise
      0  0

  2. #2

  3. #3
    Invité
    Invité(e)
    Bonjour,

    il faut arrêter la parano...
    Ça ne sert à rien de barricader sa porte si on laisse une fenêtre ouverte...

    Tu n'as pas besoin de contrôler "tout" ce que contient $_GET, mais juste ce dont tu as besoin.
    Car un bon développeur est censé savoir ce qu'il fait.


    Citation Envoyé par feelwatt Voir le message
    En $_GET je passe uniquement le nom de la page p et des fois un id
    Si tu as besoin de "p" et "id", alors c'est $_GET['p'] et $_GET['id'] qu'il faut vérifier au moment de leur récupération.

    • "id" : à priori, c'est un "numérique"
    • "p" : un nom de page. On peut définir un array des noms acceptables (les pages de ton site), et/ou un pattern à respecter.

    Ainsi, si tu es amené à passer d'autres paramètres (année, numéro de page,... ou autre), il suffira de les vérifier aussi.

    Idem pour $_POST.

  4. #4
    Membre régulier
    Ok, ok
    #MaitrePylos
    Oui, j'utilise htmlspecialchars() pour l'affichage et striptags() pour l'enregistrement en bd.

    #jreaux62,
    ok, pour la parano pardon.

    "id" : à priori, c'est un "numérique"
    "p" : un nom de page. On peut définir un array des noms acceptables (les pages de ton site), et/ou un pattern à respecter.
    Nickel et rapide:
    • id > if (is_numeric())
    • lister un array des pages et voir si le $_GET['p'] en fait partie.


    Merci.

    Ps:
    Pour l'array
    On peut:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $dir='nom_dossier';
    if($dir)
    { 
      while ($entry = $dir->read()) { 
        if (strstr($entry,'.php')) {
    	$pages_valides.=$entry.'|';
        }
      } 
    }
    Ca évite d'en oublier.
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  5. #5
    Modérateur

    Salut,
    Citation Envoyé par feelwatt Voir le message
    Ok, ok
    #MaitrePylos
    Oui, j'utilise htmlspecialchars() pour l'affichage et striptags() pour l'enregistrement en bd.
    Houlà, surtout pas striptags() pour échapper avant l'enregistrement en base de données. Ça ne sert à rien du tout.
    Chaque moteur de base de données à son propre mécanisme de protection, tu dois l'utiliser : tiens un petit topo par ici, lis la première partie.

  6. #6
    Membre régulier
    Ok merci rawsrc
    Houlà, surtout pas striptags() pour échapper avant l'enregistrement en base de données. Ça ne sert à rien du tout.
    Chaque moteur de base de données à son propre mécanisme de protection, tu dois l'utiliser : tiens un petit topo par ici, lis la première partie.
    En effet,
    dans
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    try { 
    	$sql = "UPDATE bdd_name SET col_name=? WHERE id=?";
    	$stmt = $bdd_user->prepare($sql);
    	$stmt->execute(array($valeur,$id));
    } catch(PDOException $e) {$erreur_sql='Erreur: '.$sql.'<br>'.$e->getMessage();}
    J'ai envoyé
    Code js :Sélectionner tout -Visualiser dans une fenêtre à part
    <script type="text/javascript">alert('boum');</script>

    et il ne reste que
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  7. #7
    Modérateur

    tu peux envoyer ce que tu veux à la base comme au navigateur à condition de toujours échapper correctement les données :
    - pour la base de données, c'est souvent via le mécanisme de préparation : $stmt = $pdo->prepare($sql);,
    - pour l'affichage, c'est toujours avec htmlspecialchars().

    Ainsi tu rends les données saisies par un utilisateur inoffensives quel que soit le contexte dans lequel tu évolues (base de données et/ou affichage html)

    Tu peux très bien sauvegarder en base de données la chaîne complète saisie telle quelle par l'utilisateur : <script type="text/javascript">alert('boum');</script>, tu peux aussi la renvoyer telle quelle au navigateur À CONDITION DE L'ÉCHAPPER CORRECTEMENT : echo htmlspecialchars('<script type="text/javascript">alert("boum");</script>', ENT_QUOTES, 'utf-8');

  8. #8
    Membre régulier
    J'ai du me planter
    j'ai donc envoyé
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    <script type="text/javascript">alert('boum');</script>
    Dans
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    try { $sql = "UPDATE db_name SET colonne=? WHERE id=?";
    $stmt = $bdd_user->prepare($sql);
    $stmt->execute(array($_POST['new_valeur'], $_POST['id'])));
    } catch(PDOException $e) 
    {$erreur_sql='Erreur: '.$sql.' <br>'.$e->getMessage();}

    Sans strip_tags à l'enregistrement
    et à l'affichage
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    <?php echo htmlspecialchars($results['colonne'], ENT_QUOTES, 'utf-8');?>

    Ca fait boum.

    Avec strip_tags ca enregistre alert('boum');

    Par contre écrire dans la page
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
     echo htmlspecialchars('<script type="text/javascript">alert("boum");</script>', ENT_QUOTES, 'utf-8');

    ca fait pas boum.
    Je croire que je me perd qql part...
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  9. #9
    Modérateur

    ta base de données est encodée utf-8 ? Est-ce qu'à l'ouverture de connexion tu définis le bon charset ?

  10. #10
    Membre régulier
    Salut,

    Pour la page l'encodage est:
    Code html :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    Pour les BD c'est
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    latin1_swedish_ci
    et à l'ouverture de connexion:
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    try
    {	
    	$bdd_user = new PDO("mysql:host=localhost;dbname=db_name", "root", "");
    	$bdd_user->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    catch(Exception $e)
    	{
    	die('Erreur connect bd: '.$e->getMessage());
    }
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  11. #11
    Modérateur

    avec les encodages c'est hyper simple : tu dois être homogène sur toute la ligne. A chaque étape/niveau tu dois avoir le même encodage.

    Tiens un peu de lecture par ici.

    Si ta base est vide, je te conseille de redéfinir tous les encodages et collations (base, tables) en utf-8
    Si elle ne l'est pas, tu vas être obligé d'y aller à coup d'ALTER après avoir bien tout sauvegardé (surtout !)

  12. #12
    Membre régulier
    Ok, va falloir tout remettre,
    j'avais récupéré cette base et elle est en latin1_swedish_ci
    Si elle ne l'est pas, tu vas être obligé d'y aller à coup d'ALTER après avoir bien tout sauvegardé (surtout !)
    Je vais tenter de faire une boucle sur les tables.
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  13. #13
    Membre régulier
    Ok je fais le tour des tables avec
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php 
      $bd_name='a3u12e';
      $req = $bdd_user->prepare("SHOW TABLES FROM $bd_name");
      $req->execute(array());
      while ($results=$req->fetch()) { 
        // print_r($results);
        $table_name=$results[0];
        echo $table_name;
        echo '<hr>';
      } ?>
    J'ai un souci pour y insérer la boucle pour faire le tour des colonnes
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?php 
      $bd_name='a3u12e';
      $req = $bdd_user->prepare("SHOW TABLES FROM $bd_name");
      $req->execute(array());
      while ($results=$req->fetch()) { 
        // print_r($results);
        $table_name=$results[0];
        echo $table_name;
     
        // *** Tour des colonnes
              $i=0;
              $sql = "SELECT column_name FROM information_schema.columns WHERE table_name = $table_name AND table_schema=$bd_name";
              echo $sql.'<br>';
              $req_colonnes = $bdd_user->query($sql);
                while ($colonnes = $req_colonnes->fetch(PDO::FETCH_ASSOC))
                { 
                  echo $i." => '".$colonnes['column_name']."', ";
                  $i++;
                }
        // *** Tour des colonnes
     
        echo '<hr>';
      } ?>
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain

  14. #14
    Membre régulier
    Ok,
    Je comprends je sors du sujet de départ.
    Résolu, merci.
    "Ils ne savaient pas que c'était impossible, alors ils l'ont fait." Mark Twain