¿Cómo puedo desinfectar la entrada del usuario con PHP?

¿Existe una función de captura en algún lugar que funcione bien para desinfectar la entrada del usuario para la inyección de SQL y los ataques XSS, al tiempo que permite ciertos tipos de etiquetas HTML?

preguntado el 24 de septiembre de 08 a las 18:09

Hoy en día, para evitar la inyección de sql, use PDO o MySQLi. -

Usar PDO o MySQLi no es suficiente. Si crea sus declaraciones SQL con datos que no son de confianza, como select * from users where name='$name', entonces no importa si usa PDO o MySQLi o MySQL. Sigues en peligro. Debe utilizar consultas parametrizadas o, si es necesario, utilizar mecanismos de escape en sus datos, pero eso es mucho menos preferible. -

@AndyLester ¿Está insinuando que alguien usa PDO sin declaraciones preparadas? :) -

Estoy diciendo que "Use PDO o MySQLi" no es suficiente información para explicar a los principiantes cómo usarlos de manera segura. Usted y yo sabemos que las declaraciones preparadas son importantes, pero no supongo que todos los que lean esta pregunta lo sepan. Por eso agregué las instrucciones explícitas. -

El comentario de Andy es totalmente válido. Recientemente convertí mi sitio web mysql a PDO pensando que ahora estaba de alguna manera a salvo de los ataques de inyección. Fue solo durante el proceso que me di cuenta de que algunas de mis declaraciones sql todavía se creaban utilizando la entrada del usuario. Luego lo arreglé usando declaraciones preparadas. Para un novato, no está del todo claro que exista una distinción, ya que muchos expertos descartan el comentario sobre el uso de PDO, pero no especifican la necesidad de declaraciones preparadas. La suposición es que esto es obvio. Pero no para un novato. -

17 Respuestas

Es un error común pensar que la entrada del usuario se puede filtrar. PHP incluso tiene una "función" (ahora obsoleta), llamada citas-magicas, que se basa en esta idea. No tiene sentido. Olvídate de filtrar (o limpiar, o como la gente lo llame).

Lo que debe hacer, para evitar problemas, es bastante simple: cada vez que inserta un dato dentro de un código externo, debe tratarlo de acuerdo con las reglas de formato de ese código. Pero debe comprender que tales reglas pueden ser demasiado complicadas para intentar seguirlas todas manualmente. Por ejemplo, en SQL, las reglas para cadenas, números e identificadores son todas diferentes. Para su comodidad, en la mayoría de los casos existe una herramienta dedicada para dicha incrustación. Por ejemplo, cuando necesita usar una variable PHP en la consulta SQL, debe usar una declaración preparada, que se encargará de todo el formato / tratamiento adecuado.

Otro ejemplo es HTML: si incrusta cadenas dentro del marcado HTML, debe escapar con htmlspecialchars. Esto significa que cada uno echo or print declaración debe usar htmlspecialchars.

Un tercer ejemplo podrían ser los comandos de shell: si va a incrustar cadenas (como argumentos) en comandos externos y llamarlos con exec, entonces debes usar escapeshellcmd y escapeshellarg.

Además, un ejemplo muy convincente es JSON. Las reglas son tan numerosas y complicadas que nunca podrá seguirlas todas manualmente. Es por eso que nunca debe crear una cadena JSON manualmente, pero siempre use una función dedicada, json_encode() que formateará correctamente cada bit de datos.

Y así sucesivamente y así sucesivamente ...

Los programas , solamente caso en el que necesite filtrar datos de forma activa, es si está aceptando una entrada formateada previamente. Por ejemplo, si permite que sus usuarios publiquen marcado HTML, eso es lo que planea mostrar en el sitio. Sin embargo, debe ser prudente evitar esto a toda costa, ya que no importa qué tan bien lo filtre, siempre será un potencial agujero de seguridad.

Respondido el 15 de diciembre de 20 a las 08:12

"Esto significa que cada declaración echo o print debe usar htmlspecialchars" - por supuesto, te refieres a "cada ... declaración que da salida a la entrada del usuario"; htmlspecialchars () - ifying "echo '¡Hola, mundo!';" sería una locura;) - bobby jack

Hay un caso en el que creo que el filtrado es la solución correcta: UTF-8. No desea secuencias UTF-8 no válidas en toda su aplicación (puede obtener una recuperación de error diferente según la ruta del código), y UTF-8 se puede filtrar (o rechazar) fácilmente. - Cornell

@jbyrd - no, LIKE usa un lenguaje de expresiones regulares especializado. Tendrá que escapar de su cadena de entrada dos veces: una para la expresión regular y otra para la codificación de la cadena mysql. Es código dentro de código dentro de código. - troelskn

En este momento mysql_real_escape_string es obsoleto. Hoy en día se considera una buena práctica utilizar declaraciones preparadas para evitar la inyección de SQL. Así que cambie a MySQLi o PDO. - Marcel Korpel

Porque limitas la superficie de ataque. Si desinfecta temprano (cuando ingresa), debe asegurarse de que no haya otros agujeros en la aplicación por donde puedan ingresar datos incorrectos. Mientras que si lo hace tarde, su función de salida no tiene que "confiar" en que se le proporcionen datos seguros, simplemente asume que todo es inseguro. - troelskn

No intente evitar la inyección de SQL desinfectando los datos de entrada.

En su lugar, no permita que se utilicen datos para crear su código SQL. Utilice declaraciones preparadas (es decir, utilice parámetros en una consulta de plantilla) que utilice variables vinculadas. Es la única forma de garantizar la inyección de SQL.

Por favor vea mi sitio web http://bobby-tables.com/ para obtener más información sobre cómo prevenir la inyección de SQL.

Respondido 01 Jul 15, 18:07

O visitar el documentación oficial y aprender DOP y declaraciones preparadas. Pequeña curva de aprendizaje, pero si conoce bastante bien SQL, no tendrá problemas para adaptarse. - un codificador

Para el caso específico de SQL Injection, este es la respuesta correcta! - Scott Arciszewski

Tenga en cuenta que las declaraciones preparadas no agregan seguridad, las consultas parametrizadas sí lo hacen. Resulta que son muy fáciles de usar juntos en PHP. - Básico

No es la única forma garantizada. Hex la entrada y no hexadecimal en la consulta también lo evitarán. Además, los ataques hexadecimales no son posibles si usas el derecho hechizante. - Ramón Baker

¿Qué sucede si ingresa algo especializado, como direcciones de correo electrónico o nombres de usuario? - abraham brookes

No. No puede filtrar datos genéricamente sin ningún contexto de para qué sirven. A veces, querrá tomar una consulta SQL como entrada y, a veces, querrá tomar HTML como entrada.

Debe filtrar la entrada en una lista blanca: asegúrese de que los datos coincidan con alguna especificación de lo que espera. Luego, debe escapar de él antes de usarlo, según el contexto en el que lo esté usando.

El proceso de escape de datos para SQL, para evitar la inyección de SQL, es muy diferente del proceso de escape de datos para (X) HTML, para evitar XSS.

Respondido el 23 de diciembre de 12 a las 14:12

PHP tiene las nuevas y agradables funciones filter_input ahora, que por ejemplo te liberan de encontrar 'la expresión regular de correo electrónico definitiva' ahora que hay un tipo FILTER_VALIDATE_EMAIL incorporado

Mi propia clase de filtro (usa JavaScript para resaltar campos defectuosos) puede iniciarse mediante una solicitud ajax o una publicación de formulario normal. (vea el ejemplo a continuación)

/**
 *  Pork.FormValidator
 *  Validates arrays or properties by setting up simple arrays. 
 *  Note that some of the regexes are for dutch input!
 *  Example:
 * 
 *  $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
 *  $required = array('name', 'email', 'alias', 'pwd');
 *  $sanitize = array('alias');
 *
 *  $validator = new FormValidator($validations, $required, $sanitize);
 *                  
 *  if($validator->validate($_POST))
 *  {
 *      $_POST = $validator->sanitize($_POST);
 *      // now do your saving, $_POST has been sanitized.
 *      die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
 *  }
 *  else
 *  {
 *      die($validator->getScript());
 *  }   
 *  
 * To validate just one element:
 * $validated = new FormValidator()->validate('blah@bla.', 'email');
 * 
 * To sanitize just one element:
 * $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
 * 
 * @package pork
 * @author SchizoDuckie
 * @copyright SchizoDuckie 2008
 * @version 1.0
 * @access public
 */
class FormValidator
{
    public static $regexes = Array(
            'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}\$",
            'amount' => "^[-]?[0-9]+\$",
            'number' => "^[-]?[0-9,]+\$",
            'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$",
            'not_empty' => "[a-z0-9A-Z]+",
            'words' => "^[A-Za-z]+[A-Za-z \\s]*\$",
            'phone' => "^[0-9]{10,11}\$",
            'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$",
            'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$",
            'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$",
            '2digitopt' => "^\d+(\,\d{2})?\$",
            '2digitforce' => "^\d+\,\d\d\$",
            'anything' => "^[\d\D]{1,}\$"
    );
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
    {
        $this->validations = $validations;
        $this->sanitations = $sanitations;
        $this->mandatories = $mandatories;
        $this->errors = array();
        $this->corrects = array();
    }

    /**
     * Validates an array of items (if needed) and returns true or false
     *
     */
    public function validate($items)
    {
        $this->fields = $items;
        $havefailures = false;
        foreach($items as $key=>$val)
        {
            if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
            {
                $this->corrects[] = $key;
                continue;
            }
            $result = self::validateItem($val, $this->validations[$key]);
            if($result === false) {
                $havefailures = true;
                $this->addError($key, $this->validations[$key]);
            }
            else
            {
                $this->corrects[] = $key;
            }
        }

        return(!$havefailures);
    }

    /**
     *
     *  Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
     */
    public function getScript() {
        if(!empty($this->errors))
        {
            $errors = array();
            foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; }

            $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
            $output .= "new FormValidator().showMessage();";
        }
        if(!empty($this->corrects))
        {
            $corrects = array();
            foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; }
            $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';   
        }
        $output = "<script type='text/javascript'>{$output} </script>";
        return($output);
    }


    /**
     *
     * Sanitizes an array of items according to the $this->sanitations
     * sanitations will be standard of type string, but can also be specified.
     * For ease of use, this syntax is accepted:
     * $sanitations = array('fieldname', 'otherfieldname'=>'float');
     */
    public function sanitize($items)
    {
        foreach($items as $key=>$val)
        {
            if(array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
            $items[$key] = self::sanitizeItem($val, $this->validations[$key]);
        }
        return($items);
    }


    /**
     *
     * Adds an error to the errors array.
     */ 
    private function addError($field, $type='string')
    {
        $this->errors[$field] = $type;
    }

    /**
     *
     * Sanitize a single var according to $type.
     * Allows for static calling to allow simple sanitization
     */
    public static function sanitizeItem($var, $type)
    {
        $flags = NULL;
        switch($type)
        {
            case 'url':
                $filter = FILTER_SANITIZE_URL;
            break;
            case 'int':
                $filter = FILTER_SANITIZE_NUMBER_INT;
            break;
            case 'float':
                $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
            break;
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_SANITIZE_EMAIL;
            break;
            case 'string':
            default:
                $filter = FILTER_SANITIZE_STRING;
                $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
            break;

        }
        $output = filter_var($var, $filter, $flags);        
        return($output);
    }

    /** 
     *
     * Validates a single var according to $type.
     * Allows for static calling to allow simple validation.
     *
     */
    public static function validateItem($var, $type)
    {
        if(array_key_exists($type, self::$regexes))
        {
            $returnval =  filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
            return($returnval);
        }
        $filter = false;
        switch($type)
        {
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_VALIDATE_EMAIL;    
            break;
            case 'int':
                $filter = FILTER_VALIDATE_INT;
            break;
            case 'boolean':
                $filter = FILTER_VALIDATE_BOOLEAN;
            break;
            case 'ip':
                $filter = FILTER_VALIDATE_IP;
            break;
            case 'url':
                $filter = FILTER_VALIDATE_URL;
            break;
        }
        return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
    }       



}

Por supuesto, tenga en cuenta que también debe realizar el escape de su consulta SQL dependiendo del tipo de base de datos que esté utilizando (mysql_real_escape_string () es inútil para un servidor SQL, por ejemplo). Probablemente desee manejar esto automáticamente en su capa de aplicación apropiada como un ORM. Además, como se mencionó anteriormente: para la salida a html use las otras funciones dedicadas de php como htmlspecialchars;)

Para permitir realmente la entrada HTML con clases y / o etiquetas similares, depende de uno de los paquetes de validación xss dedicados. ¡NO ESCRIBA SUS PROPIOS REGEXES EN HTML PARSE!

Respondido 08 Jul 19, 14:07

Parece que puede ser un script útil para validar entradas, pero es completamente irrelevante para la pregunta. - rjmunro

No no hay.

En primer lugar, la inyección de SQL es un problema de filtrado de entrada y XSS es una salida que se escapa, por lo que ni siquiera ejecutaría estas dos operaciones al mismo tiempo en el ciclo de vida del código.

Reglas generales básicas

  • Para consultas SQL, vincule parámetros (como con PDO) o use una función de escape nativa del controlador para variables de consulta (como mysql_real_escape_string())
  • Utilice las strip_tags() para filtrar HTML no deseado
  • Escape de todas las demás salidas con htmlspecialchars() y tenga en cuenta los parámetros segundo y tercero aquí.

Respondido el 24 de Septiembre de 08 a las 21:09

Entonces, solo usa strip_tags () o htmlspecialchars () cuando sabe que la entrada tiene HTML del que desea deshacerse o escapar respectivamente; no lo está usando para ningún propósito de seguridad, ¿verdad? Además, cuando haces el enlace, ¿qué hace con cosas como Bobby Tables? "Robert '); DROP TABLE Estudiantes; -" ¿Se escapa de las comillas? - Roberto Marcos Bram

Si tiene datos de usuario que irán a una base de datos y luego se mostrarán en páginas web, ¿no suele leerse mucho más de lo que está escrito? Para mí, tiene más sentido filtrarlo una vez (como entrada) antes de almacenarlo, en lugar de tener que filtrarlo cada vez que lo muestra. ¿Me estoy perdiendo algo o un grupo de personas votó por una sobrecarga de rendimiento innecesaria en esto y la respuesta aceptada? - jbo5112

La mejor respuesta para mi Es breve y responde bien a la pregunta si me preguntas. ¿Es posible atacar PHP de alguna manera a través de $ _POST o $ _GET con alguna inyección o es imposible? - jo smo

oh, sí, las matrices $ post y $ get aceptan todos los caracteres, pero algunos de esos caracteres se pueden usar en su contra si se permite que el carácter se enumere en la página php publicada. así que si no escapa de encapsular caracteres (como ", 'y`) podría abrir un vector de ataque. El carácter `a menudo se pasa por alto y se puede usar para formar hacks de ejecución de línea de comando. El saneamiento evitará la piratería de entrada del usuario, pero no le ayudará con los hackeos del firewall de aplicaciones web. drtechno

Para abordar el problema de XSS, eche un vistazo a Purificador de HTML. Es bastante configurable y tiene un historial decente.

En cuanto a los ataques de inyección SQL, asegúrese de verificar la entrada del usuario y luego ejecutarlo a través de mysql_real_escape_string (). Sin embargo, la función no anulará todos los ataques de inyección, por lo que es importante que verifique los datos antes de volcarlos en su cadena de consulta.

Una mejor solución es utilizar declaraciones preparadas. La Biblioteca PDO y la extensión mysqli son compatibles con estos.

Respondido el 24 de Septiembre de 08 a las 21:09

no hay una "mejor manera" de hacer algo como desinfectar la entrada. Use alguna biblioteca, el purificador html es bueno. Estas bibliotecas han sido golpeadas muchas veces. Así que es mucho más a prueba de balas que cualquier cosa que puedas encontrar tú mismo. paan

El problema con wordpress es que no es necesariamente un ataque de inyección php-sql el que causa brechas en la base de datos. La falta de complementos programados que almacenan datos que una consulta xml revela secretos es más problemática. - drtechno

PHP 5.2 introdujo el filter_var función.

Es compatible con una gran cantidad de filtros SANITIZE, VALIDATE.

http://php.net/manual/en/function.filter-var.php

Respondido 15 Oct 12, 09:10

Métodos para desinfectar la entrada del usuario con PHP:

  • Utilice versiones modernas de MySQL y PHP.

  • Establecer juego de caracteres explícitamente:

    • $ mysqli-> set_charset ("utf8");
      manual
    • $ pdo = nuevo PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ usuario, $ contraseña);
      manual
    • $ pdo-> exec ("establecer nombres utf8");
      manual
    • $ pdo = new PDO ("mysql: host = $ host; dbname = $ db", $ user, $ pass, array (PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION, PDO :: MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ));
      manual
    • mysql_set_charset ('utf8')
      [obsoleto en PHP 5.5.0, eliminado en PHP 7.0.0].
  • Utilice juegos de caracteres seguros:

    • Seleccione utf8, latin1, ascii .., no use conjuntos de caracteres vulnerables big5, cp932, gb2312, gbk, sjis.
  • Usar función espacializada:

    • Declaraciones preparadas por MySQLi:
      $ stmt = $ mysqli-> prepare ('SELECT * FROM test WHERE name =? LIMIT 1'); 
      $ param = "'OR 1 = 1 / *";
      $ stmt-> bind_param ('s', $ param);
      $ stmt-> ejecutar ();
    • DOP :: cotización () - coloca comillas alrededor de la cadena de entrada (si es necesario) y escapa los caracteres especiales dentro de la cadena de entrada, utilizando un estilo de comillas apropiado para el controlador subyacente:

      $ pdo = nuevo PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ usuario, $ contraseña);establecer explícitamente el juego de caracteres
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, falso);deshabilite la emulación de declaraciones preparadas para evitar el retorno a la emulación de declaraciones que MySQL no puede preparar de forma nativa (para evitar la inyección)
      $ var = $ pdo-> quote ("'OR 1 = 1 / *");no solo escapa del literal, sino que también lo cita (en caracteres de comillas simples) $ stmt = $ pdo-> query ("SELECT * FROM test WHERE name = $ var LIMIT 1");

    • Declaraciones preparadas de PDO: vs declaraciones preparadas de MySQLi admiten más controladores de bases de datos y parámetros con nombre:

      $ pdo = nuevo PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ usuario, $ contraseña);establecer explícitamente el juego de caracteres
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, falso);deshabilite la emulación de declaraciones preparadas para evitar el retorno a la emulación de declaraciones que MySQL no puede preparar de forma nativa (para evitar la inyección) $ stmt = $ pdo-> prepare ('SELECT * FROM test WHERE name =? LIMIT 1'); $ stmt-> ejecutar (["'OR 1 = 1 / *"]);

    • mysql_real_escape_cadena [obsoleto en PHP 5.5.0, eliminado en PHP 7.0.0].
    • mysqli_real_escape_cadena Escapa de los caracteres especiales de una cadena para su uso en una declaración SQL, teniendo en cuenta el juego de caracteres actual de la conexión. Pero se recomienda usar declaraciones preparadas porque no son simplemente cadenas de escape, una declaración genera un plan completo de ejecución de consultas, incluidas las tablas e índices que usaría, es una forma optimizada.
    • Use comillas simples ('') alrededor de sus variables dentro de su consulta.
  • Compruebe que la variable contiene lo que espera:

    • Si espera un número entero, use:
      ctype_digit: comprueba si hay caracteres numéricos;
      $ valor = (int) $ valor;
      $ valor = intval ($ valor);
      $ var = filter_var ('0755', FILTER_VALIDATE_INT, $ opciones);
    • Para uso de cadenas:
      is_string () - Encuentra si el tipo de una variable es una cadena

      Utilice las Función de filtro filter_var () - filtra una variable con un filtro especificado:
      $ correo electrónico = filter_var ($ correo electrónico, FILTER_SANITIZE_EMAIL);
      $ newstr = filter_var ($ str, FILTER_SANITIZE_STRING);
      filtros más predefinidos
    • filter_input () - Obtiene una variable externa específica por nombre y, opcionalmente, la filtra:
      $ search_html = filter_input (INPUT_GET, 'buscar', FILTER_SANITIZE_SPECIAL_CHARS);
    • preg_match () - Realizar una coincidencia de expresión regular;
    • Escriba su propia función de validación.

Respondido 25 Feb 18, 08:02

Un truco que puede ayudar en la circunstancia específica en la que tienes una página como /mypage?id=53 y usa la identificación en una cláusula WHERE para asegurarse de que la identificación sea definitivamente un número entero, así:

if (isset($_GET['id'])) {
  $id = $_GET['id'];
  settype($id, 'integer');
  $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
  # now use the result
}

Pero, por supuesto, eso solo elimina un ataque específico, así que lea todas las demás respuestas. (Y sí, sé que el código anterior no es excelente, pero muestra la defensa específica).

respondido 08 mar '10, 23:03

Yo uso $ id = intval ($ id) en su lugar :) - Duc Tran

La conversión de números enteros es una buena manera de garantizar que solo se inserten datos numéricos. - test

$id = (int)$_GET['id'] y $que = sprintf('SELECT ... WHERE id="%d"', $id) también es bueno - Vladkras

quizás if (isset($_GET['id']) { if !( (int) $_GET['id'] === intval($_GET['id'] ) ) { throw new \InvalidArgumentException('Invalid page id format'); } /* use a prepared statement for insert here */ }; podría adaptarse a usted. Prefiero no realizar ninguna llamada a la base de datos si puedo identificar que un parámetro definitivamente no es válido en función del esquema conocido al que se está transfiriendo. - mopsid

Lo que está describiendo aquí son dos temas separados:

  1. Desinfección / filtrado de datos de entrada del usuario.
  2. Salida de escape.

1) Siempre se debe suponer que la entrada del usuario es incorrecta.

Definitivamente es imprescindible usar declaraciones preparadas y / o filtrar con mysql_real_escape_string. PHP también tiene filter_input integrado, que es un buen lugar para comenzar.

2) Este es un tema extenso y depende del contexto de los datos que se generan. Para HTML existen soluciones como htmlpurifier. como regla general, siempre evite todo lo que genere.

Ambos problemas son demasiado grandes para abordarlos en una sola publicación, pero hay muchas publicaciones que entran en más detalles:

Métodos de salida PHP

Salida PHP más segura

Respondido 18 Feb 13, 07:02

No hay una función de captura, porque hay varias preocupaciones que deben abordarse.

  1. SQL Injection - Hoy, en general, todos los proyectos PHP deberían usar declaraciones preparadas a través de PHP Data Objects (PDO) como una mejor práctica, prevenir un error de una cotización perdida, así como una solución completa contra la inyección. También es la forma más flexible y segura de acceder a su base de datos.

    Comprar (El único tutorial adecuado) de PDO para prácticamente todo lo que necesita saber sobre la DOP. (Nuestro más sincero agradecimiento al principal colaborador de SO, @YourCommonSense, por este gran recurso sobre el tema).

  2. XSS: desinfecte los datos en el camino en ...

    • Purificador de HTML ha existido durante mucho tiempo y todavía se actualiza activamente. Puede usarlo para desinfectar la entrada maliciosa, al mismo tiempo que permite una lista blanca generosa y configurable de etiquetas. Funciona muy bien con muchos editores WYSIWYG, pero puede resultar pesado para algunos casos de uso.

    • En otros casos, en los que no queremos aceptar HTML / Javascript en absoluto, he encontrado útil esta función simple (y ha pasado varias auditorías contra XSS):

      /* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }

  3. XSS: desinfecte los datos al salir ... A menos que garantice que los datos se desinfectaron adecuadamente antes de agregarlos a su base de datos, deberá desinfectarlos antes de mostrárselos a su usuario, podemos aprovechar estas útiles funciones de PHP:

    • Cuando usted llama echo or print para mostrar los valores proporcionados por el usuario, utilice htmlspecialchars a menos que los datos se hayan desinfectado adecuadamente, sean seguros y se les permita mostrar HTML.
    • json_encode es una forma segura de proporcionar valores proporcionados por el usuario desde PHP a Javascript
  4. ¿Llamas a comandos de shell externos usando exec() or system() funciones, o al backtick ¿operador? Si es así, además de SQL Injection y XSS, es posible que tenga una inquietud adicional que abordar, usuarios que ejecutan comandos maliciosos en su servidor. Necesitas usar escapeshellcmd si desea escapar del comando completo O escapeshellarg para escapar de las discusiones individuales.

Respondido el 19 de diciembre de 17 a las 20:12

¿Se podría utilizar mb_encode_numericentity en su lugar? ¿Ya que codifica todo? - drtechno

@drtechno - mb_encode_numericentity se discute en el htmlspecialchars enlace en # 3 XSS - Webaholik

Por lo que sé, XSS es una preocupación de salida, no de entrada. - bam

@bam: tienes razón, ¡no te pierdas ni un lugar! Afortunadamente, la mayoría de los frameworks se encargarán de nosotros cuando se utilicen correctamente. - Webaholik

Si está utilizando PostgreSQL, la entrada de PHP se puede escapar con pg_escape_string ()

 $username = pg_escape_string($_POST['username']);

De la documentación (http://php.net/manual/es/function.pg-escape-string.php):

pg_escape_string () escapa una cadena para consultar la base de datos. Devuelve una cadena de escape en formato PostgreSQL sin comillas.

Respondido 24 Abr '18, 12:04

pg_escape_literal () es la función recomendada para usar con PostgreSQL. - críptico ツ

La forma más fácil de evitar errores al desinfectar la entrada y escapar de los datos es utilizando un marco PHP como Symfony, Nette etc. o parte de ese marco (motor de plantillas, capa de base de datos, ORM).

Motor de plantillas como Ramita o Latte tiene salida de escape de forma predeterminada; no tiene que resolver manualmente si ha escapado correctamente de su salida según el contexto (parte HTML o Javascript de la página web).

Framework desinfecta automáticamente la entrada y no debe usar las variables $ _POST, $ _GET o $ _SESSION directamente, sino a través de mecanismos como enrutamiento, manejo de sesiones, etc.

Y para la capa de base de datos (modelo) hay marcos ORM como Doctrine o envoltorios alrededor de PDO como Nette Database.

Puedes leer más sobre esto aquí - ¿Qué es un marco de software?

Respondido 23 Feb 18, 17:02

Solo quería agregar eso sobre el tema del escape de salida, si usa php DOMDocument para hacer su salida html, escapará automáticamente en el contexto correcto. Un atributo (valor = "") y el texto interno de a no son iguales. Para estar seguro contra XSS, lea esto: Hoja de trucos de prevención de OWASP XSS

respondido 17 nov., 14:21

Nunca desinfecta la entrada.

Siempre desinfecta la salida.

Las transformaciones que aplica a los datos para que su inclusión en una declaración SQL sea segura son completamente diferentes de las que solicita para su inclusión en HTML son completamente diferentes de las que solicita para su inclusión en Javascript son completamente diferentes de las que solicita para su inclusión en LDIF son completamente diferentes de los que aplica para la inclusión en CSS son completamente diferentes de los que solicita para la inclusión en un correo electrónico ...

Por todos los medios validar entrada - decidir si debe aceptarlo para su posterior procesamiento o informar al usuario que es inaceptable. Pero no aplique ningún cambio a la representación de los datos hasta que esté a punto de salir de PHP.

Hace mucho tiempo, alguien intentó inventar un mecanismo único para escapar de datos y terminamos con "citas_mágicas"que no escapó correctamente los datos para todos los destinos de salida y dio como resultado una instalación diferente que requirió un código diferente para funcionar.

Respondido el 20 de junio de 20 a las 10:06

Un problema con eso es que no siempre es un ataque a la base de datos, y todas las entradas del usuario deben protegerse del sistema. no solo un tipo de idioma. Entonces, en sus sitios, cuando enumera sus datos $ _POST, incluso con el uso de un enlace, podría escapar lo suficiente como para ejecutar shell o incluso otro código php. - drtechno

"no siempre es un ataque a la base de datos": "Las transformaciones que aplica a los datos para que sean seguros para su inclusión en una declaración SQL son completamente diferentes de las ..." symcbean

"Todas las entradas del usuario deben protegerse del sistema": no, el sistema debe protegerse de las entradas del usuario. - symcbean

Bueno, me quedé sin palabras, pero sí, se debe evitar que la entrada afecte el funcionamiento del sistema. para aclarar esto ... - drtechno

Tanto la entrada como la salida deben desinfectarse. - Jsowa

Existe la extensión del filtro (cómo enlazar, manual), que funciona bastante bien con todas las variables de GPC. Sin embargo, no es una cosa mágica, aún tendrás que usarla.

Respondido el 24 de Septiembre de 08 a las 21:09

Nunca confíe en los datos del usuario.

function clean_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}

Los programas trim() La función elimina los espacios en blanco y otros caracteres predefinidos de ambos lados de una cadena.

Los programas stripslashes() función elimina barras invertidas

Los programas htmlspecialchars() La función convierte algunos caracteres predefinidos en entidades HTML.

Los caracteres predefinidos son:

& (ampersand) becomes &amp;
" (double quote) becomes &quot;
' (single quote) becomes &#039;
< (less than) becomes &lt;
> (greater than) becomes &gt;

Respondido 15 Oct 18, 09:10

¿De qué protegería esto? ¿Es esto para XSS? Por que se llama clean_input ¿luego? ¿Por qué querrías quitar las barras? - dharma

ADVERTENCIA: Esto no protege mágicamente los datos del usuario. Esta función dañará innecesariamente sus datos sin protegerlos de nada. ¡NO LO USES! - dharma

Tu declaración es falsa. - erik thiart

Creo que esta función se puede usar para la salida, en cuyo caso no hablaremos de desinfección sino de escape. Realmente no entiendo la importancia de stripslashes(). También puede ver lo que la gente en WordPress estás haciendo. - bam

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.