PHP: Uso adecuado de parse_str

La siguiente porción de código es una práctica muy extendida en WordPress, sirve para que las funciones puedan tener un buen número de parámetros opcionales sin que el código sea visualmente feo:

php:
<?php
/* Funciones de WordPress */
function stripslashes_deep($value) {
         $value = is_array($value) ?
                 array_map('stripslashes_deep', $value) :
                 stripslashes($value);

         return $value;
}
function wp_parse_str( $string, &$array ) {
        parse_str( $string, $array );
        if ( get_magic_quotes_gpc() )
                $array = stripslashes_deep( $array );
        return $array;
}
/* Fin */

function get_posts( $args = '' ) {
        $defaults = array(
                'limit' => 5,
                'post_type' => ''
        );
        $args = wp_parse_str($args, $defaults);
       
        extract($args, EXTR_SKIP);
       
        $where = '';
        if ( !empty($post_type) )
                $where = "WHERE post_type = '$post_type'";
       
        $sql = "SELECT * FROM posts $where LIMIT $limit";
        // ejecutar la consulta en una base de datos MySQL
        echo htmlspecialchars($sql);
}

$limit = empty($_GET['limit']) ? 5 : (int) $_GET['limit'];

if (get_magic_quotes_gpc())
        $_GET['type'] = stripslashes($_GET['type']);
// Se usa addslashes sólo para el ejemplo.
// $type = mysql_real_escape_string($_GET['type']);
$type = addslashes($_GET['type']);
get_posts("limit=$limit&post_type=$type");
?>

Sobre el ejemplo mostrado:

  1. ¿Tiene algún problema de seguridad?
  2. ¿Qué pasa si cambiamos la línea resaltada por esta otra, tiene algún problema de seguridad?
    php:
    $where = "WHERE post_type = '". addslashes($post_type) . "'";

Para los interesados en este pequeño quiz, subí una página en la que pueden realizar sus pruebas.

17 Replies to “PHP: Uso adecuado de parse_str”

  1. Hola, alguien me puede explicar de que codificacion se trata %2527 = %27 = ', pensaba que era utf pero no lo creo. Me gustaria saber el por que de la doble codificación. El enlace que puso g30rg3_x no me servio de mucho, quiza algo en castellano?

    Saludos y gracias de antemano

  2. @g30rg3_x: Todavía queda otro problema de SQL Injection 😉

    @jdeveloper: Simplemente está codificando el apóstrofe dos veces.

    php:

    <?php echo urlencode(urlencode('\'')); ?>

    Se hace esto para que la función addslashes no tenga ningún efecto sobre el valor de $_GET['type']="algo%27", este último se convierte en $post_type="algo'" gracias a la acción de parse_str.

    Puedes ver un ejemplo en la página de prueba.

    Saludos

  3. gracias alex, en cuanto tenga tiempo lo mirare mas detenidamente, pero ya voy pillando la dinamica a seguir.

  4. Bueno sigo sin ver lo que creo que estas pidiendo..
    Pero mirando con mas detenimiento veo un medio-SQL-injection en $limit, ya que parse_str nos permite sobreescribir variables locales (http://www.acid-root.new.fr/advisories/14070612.txt) podriamos llamar a algo asi...

    ?limit=2&type=foo%26limit=bar

    Asi basicamente estamos pasando el filtro de solo numeros (o mejor dicho el casting a integer) que hay un poco mas arriba, aunque claro no obtendremos nada beneficioso ya que nos encontramos de tras de un LIMIT pero talvez nos podria servir para sacar informacion.

    Aunque como te dije aun no le veo por donde intente meter arrays durante pero ninguna de mis pruebas me dio positivo, asi que yo tambien quedo al pendiente de la solucion de la segunda parte...

    Saludos alex...

  5. g30rg3_x, justamente me refería a ese problema, puesto que con valores parecidos (?limit=2&type=foo%26limit=1%20UNION%20ALL%20...) al que mencionas, se sobreescribe el valor de la variable limit haciendo posible la inyección de SQL.

    sql:

    SELECT * FROM posts WHERE post_type = 'foo' LIMIT 1 UNION ALL ...

    [...], aunque claro no obtendremos nada beneficioso ya que nos encontramos de tras de un LIMIT [...]

    Eso es correcto siempre y cuando se haga uso de ORDER BY en la consulta, pero como en el ejemplo no existe esa parte se puede construir sentencias SQL perfectamente válidas.

    En el comentario anterior hacía referencia a arrays, porque básicamente al ser éstas tablas hash, la última asignación a una misma llave (limit) es la que cuenta.

    Saludos

  6. jejejejeje..

    Se me fue me concentre tanto en post_type que no le di importancia, si perdon error mio lapsus brutus de conocimiento de sql...

    Saludos

Comments are closed.