Claro magic quote off

From ClaroDevel

Etat d'avancement

Etat d'avancement de l'utilisation de la fonction claro_unquote_gpc()

Les outils suivants utilisent la fonction:

  • Announcements, Calendar, Chat, Course Description, Course Home, Course Info, Create Course, Document & Links, Exercises, Forum and Forum Admin, Groups, LearningPath, Linker, User, Tracking, Wiki, Work, Library Folder (claroline/inc/lib), Admin folder and Kernel.

TODO:

  • Scripts in admin/develTools and admin/technical.

Magic Quote GPC Off

Expliquation

Claroline et magic_quote_gpc 19 mai 2005 - Hugues Peeters

magic_quote_gpc est un paramètre d'initialisation de PHP qui échappe automatiquement les caractères ' (simple guillement), " (double guillemet) et \ (backslash) sur toute les chaînes de cratères provenant de GET, POST et COOKIES.

Ce paramètre a été introduit dans PHP pour protéger les requêtes SQL dans le code. Cependant magic_quote_gpc introduit autant de problèmse qu'il n'en résout. Car toute les variables utilisées dans la construction des requêtes SQL ne proviennent pas de GET, POST et COOKIES, et, au fur à mesure que le code gonfle, il devient rapidement complexe d'identifier quand il y a lieu d'échapper ces variables ou non.

C'est pourquoi les nouvelles distribution de PHP désactivent par défaut magic_quote_gpc. Or, Claroline a été développé en supposant que magic_quote_gpc est activé. Il faut donc trouver une solution à ce problème.

Depuis quelques temps, certains endroit du code de Claroline utilisent la fonction claro_add_slashes(), proposée par Sébastien.

/**
 * Add slashes to $text if it has not be automatically done by magic_quotes
 * Use this function _ONLY_ for vars that are affected by magic_quote_gpc
 *
 * @author Piraux Sébastien <pir@cerdecam.be>
 * @param string text to add slashes in
 * @return string $text without change if magi_quote_gpc is on,
 * addslahed $text else
 * @desc Use this only for get/post/cookies vars, not for lang vars,...
 */

function claro_addslashes($text)
{
  if( get_magic_quotes_gpc() && !defined('CL_GPC_UNQUOTED') )
  {
    // magic_quote_gpc is on : do not addslashes
    return $text;
  }
  else
  {
    // magic_quote_gpc is off : addslashes
    return addslashes($text);
  }
}

Cette fonction ne résout que partiellement le problème, car, comme le spécifie sa documentation, elle ne peut être utilisée que sur les variables susceptibles d'être affectées par magic_quote_gpc, à savoir des variables provenant de GET, POST ou COOKIES. Le développeur doit donc à chaque fois retrouver la source d'affectation des variables qu'il utilise. C'est assez problématique, surtout dans le cas de développement de librairies.

Le présent texte présente une autre manière de procéder qui pourrait résoudre définitivement les problèmes liés au magic_quote_gpc.

1. Développer le code de Claroline en supposant que, par défaut, magic_quote_gpc est désactivé.

2. Echapper les caractères problématiques (', ", \), le plus tard possible dans le code, c'est-à-dire au moment d'exécuter la requête SQL.

Exemple :

$sql = "SELECT col_1, col_2, col_3
        FROM dummy_table
        WHERE condition = addslashes($variable)";

$result = claro_sql_query_fetch_all($sql);

3. Dans tous les scripts où le code est (ré)écrit en conformité avec les points 1 et 2, appeler en début de script la fonction claro_unquote_gpc() définie dans la librairie principale de Claroline.

/**
 * strip the slashes coming from browser request
 *
 * @author Hugues Peeters <peeters@ipm.ucl.ac.be>
 * @return void
 * @desc If the php.ini setting MAGIC_QUOTE_GPC is set to ON, all the variables
 *       content comming frome the browser are automatically quoted by adding
 *       slashes (default setting before PHP 4.3). claro_unquote_gpc() removes
 *       these slashes. It needs to be called just once at the biginning
 *       of the script.
 *
 */

function claro_unquote_gpc()
{
  if ( ! defined('CL_GPC_UNQUOTED'))
  {
      if ( get_magic_quotes_gpc() == 1 )
      {
          array_walk($_GET,     'claro_stripslashes_for_unquote_gpc');
          array_walk($_POST,    'claro_stripslashes_for_unquote_gpc');
          array_walk($_REQUEST, 'claro_stripslashes_for_unquote_gpc' );
          array_walk($_COOKIE,  'claro_stripslashes_for_unquote_gpc' );
      }

      define('CL_GPC_UNQUOTED', true);
  }
}

Note. Aucun risque que la fonction soit exécutée deux fois de suite. La première exécution de la fonction définit une constante signifiant qu'elle a déjà été exécutée.

/**
 * special function for claro_unquote_gpc()
 *
 * @author Hugues Peeters <peeters@ipm.ucl.ac.be>
 * @return void
 *
 * @desc This function is needed rather a simple stripslashes for two
 *       reasons.
 *       First the PHP function array_walk() works only with user functions,
 *       not PHP ones. Second, the submitted array could be an array of 
 *       arrays, and all the values has to be treated.
 */

function claro_stripslashes_for_unquote_gpc( &$var )
{
  if (is_array($var) ) array_walk($var, 'claro_stripslashes_for_unquote_gpc');
  else                 $var = stripslashes($var);
}

Note. Cette fonction est nécessaire pour deux raisons. (1) claro_unquote_gpc() s'appuye sur la fonction PHP array_walk() qui ne fonctionne qu'avec des fonctions définies par l'utilisateur -- (2) claro_stripslashes_for_unquote_gpc() est en mesure de fonctionner de manière récursive. C'est important, car des tableaux peuvent être envoyés en GET ou en POST.

Une fois que tous les scripts auront été (ré)écrits en observant cette procédure, nous pourrons remonter claro_unquote_gpc() dans l'init de Claroline. Et le problème des magic_quote_gpc sera derrière nous.

La plus grosse difficulté pour introduire ce procédé viendra de la réécriture des librairies, car les librairies sont utilisées par plusieurs scripts. Ces scripts devront donc réécrits en même temps que la librairie.


Note. (18 mars 2006) La fonction claro_unquote_gpc() a été réécrite dans Claroline 1.8 de sorte à éviter récursivité. Le principe de récursivité peut faire gonfler la pile dédiée à la fonction. C'est une source de vulnérabilité puisque les données traitées par claro_unquote_gpc() proviennent de l'extérieur.

/**
* Strip the slashes coming from browser request
*
* If the php.ini setting MAGIC_QUOTE_GPC is set to ON, all the variables
* content comming frome the browser are automatically quoted by adding
* slashes (default setting before PHP 4.3). claro_unquote_gpc() removes
* these slashes. It needs to be called just once at the biginning
* of the script.
* @author Hugues Peeters <peeters@ipm.ucl.ac.be>
*
* @return void
*/
function claro_unquote_gpc()
{
   if ( ! defined('CL_GPC_UNQUOTED') )
   {
       if ( get_magic_quotes_gpc() )
       {
        /*
         * The new version is written in a safer approach inspired by Ilia
         * Alshanetsky. The previous approach which was using recursive
         * function permits to smash the stack and crash PHP. For example if
         * the user supplies a very deep multidimensional array, such as
         * foo[][][][] ..., the recursion can reach the point of exhausting
         * the stack. Generating such an attack is quite trivial, via the
         * use of :
         *
         *    str_repeat() function example $str = str_repeat("[]", 100000);
         *    file_get_contents("http://sitre.com.scriptphp?foo={$str}");
         */
           $inputList = array(&$_REQUEST, &$_GET, &$_POST,
                              &$_COOKIE , &$_ENV, &$_SERVER);
           while ( list($topKey, $array) = each($inputList) )
           {
               foreach( $array as $childKey => $value)
               {
                   if ( ! is_array($value) )
                   {
                       $inputList[$topKey][$childKey] = stripslashes($value);
                   }
                   else
                   {
                       $inputList[] =& $inputList[$topKey][$childKey];
                   }
               }
           }
           define('CL_GPC_UNQUOTED', true);
       } // end if get_magic_quotes_gpc
   }
}