Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Temas relacionados > Seguridad
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Cross Site Scripting (XSS)

Hola a todos,

Acabo de recibir un correo de alguien que se interesó por Loturak (y venga con Loturak, qué pesado...) hasta el punto de hacer algunas pruebas... comprometodoras. El caso es que me informa de la posibilidad de conseguir realizar "Cross Site Scripting (XSS)" en la aplicación. Ha sido tan amable que me ha enviado dos URLs de ejemplo:

Código:
http://loturak.es/compartir?p=2&demo"><script>alert(123)</script>

http://loturak.es/compartir?n=20&o=fd&b=demo" onmouseover=alert(123) "

Y bien. Yo me dispongo a investigar el tema, pero, ¿se os ocurre algo? ¿qué puede estar sucediendo? ¿Cómo podría evitarse? ¿Qué demonios significa esa variable de nombre "demo"? ¿Cómo se consigue al cabo que se ejecute el JavaScript? ¿Hasta qué punto compromete la seguridad esto? Huf, huf, huf...

Gracias desde aquí a quien me envió la información. No revelo su nombre por si no le apetece. Ya le remití un correo con mi agradecimiento, entre otras cosas. Y gracias a vosotros también por cualquier comentario que tengáis a bien hacer sobre todo esto.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #2  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

El problema con la primera URL solucionado... o eso creo, de momento. Se trataba de cierta función utilizada para propagar variables "GET". Precisamente, esta función no la escribí yo de mi copete, sino que más bien la adapté de cierto código, como puede verse:

Código PHP:
/**
 * Propaga las variables contenidas en $_GET en la URL de la página que
 * llame a esta función. Utilizamos esta función básicamente para la pa-
 * ginación de enlaces.
 *
 * El algoritmo principal de esta función está tomado del Script Paginator
 * escrito por Jorge Pinedo Rosas (http://jpinedo.webcindario.com)
 *
 * @author dec
 * @since 0.0.1
 * @access private
 * @param string $menosEstaVar Nombre de la variable que no debe propagarse
 * @return string
 */
function PropagarVariblesGet($menosEstaVar '')
{
  
$qs '';
    if((
$menosEstaVar != '')
     && isset(
$_GET[$menosEstaVar]))
      unset(
$_GET[$menosEstaVar]);

  
$aPropagar array_keys($_GET);
  foreach(
$aPropagar as $varGet)
  {
       if(isset(
$GLOBALS[$varGet])) {
          
$qs.= $varGet."=".$GLOBALS[$varGet]."&";
      }
     elseif(isset(
$_REQUEST[$varGet])) {
         
$qs.= $varGet."=".$_REQUEST[$varGet]."&";
     }
    } 
// endfor

  
return $qs;

Pues bien. Escapando las variables que nos llegan conseguimos salvar el obstáculo puesto por la primera URL. Es decir, la función ha quedado así de momento:

Código PHP:
function PropagarVariblesGet($menosEstaVar '')
{
  global 
$bdatos;  // Nuevo

  
$qs '';
    if((
$menosEstaVar != '')
     && isset(
$_GET[$menosEstaVar]))
      unset(
$_GET[$menosEstaVar]);

  
$aPropagar array_keys($_GET);
  foreach(
$aPropagar as $varGet)
  {
      
$varGet $bdatos->Escapar($varGet); // Nuevo
       
if(isset($GLOBALS[$varGet])) {
          
$qs.= $varGet."=".$GLOBALS[$varGet]."&";
      }
     elseif(isset(
$_REQUEST[$varGet])) {
         
$qs.= $varGet."=".$_REQUEST[$varGet]."&";
     }
    } 
// endfor

  
return $qs;

Aún estoy con la segunda de las URLs... ¿qué os parece de todo esto? ¿Curioso cuando menos no?

Por cierto, el método "Escapar" de la clase "Bdatos" y es tal cual:

Código PHP:
    /**
     * Escapa una cadena para su inserción en la base de datos.
     *
     * Atención: este método no asegura la entrada del usuario, que es algo
     * que deberá hacer en todo caso por otros medios.
     *
   * @author dec
   * @since 0.0.1
   * @version 1.0
     * @param string $cadena Cadena a escapar.
     * @return string
     */
    
function Escapar($cadena) {
        return 
mysql_real_escape_string(stripslashes
         
(strip_tags($cadena)), $this->enlaceConexionBd);
    }
    
/* function */ 
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #3  
Antiguo 04-12-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
¿Cómo lees los parámetros de entrada? Creo que sería útil pasarles un strip_tags.

// Saludos
Responder Con Cita
  #4  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Cita:
Empezado por Román
¿Cómo lees los parámetros de entrada? Creo que sería útil pasarles un strip_tags.
Creo que me he adelantado. Confírmamelo Román, por favor.

Por otro lado, a ver qué ocurre con la segunda URL...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #5  
Antiguo 04-12-2006
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por dec
¿Cómo se consigue al cabo que se ejecute el JavaScript?
Pues insertando el script dentro del código de tu pagina.

Donde debería de aparecer esto:
Código:
<a href="/compartir?p=1" title="Mostrar la página anterior">
Pasa a aparecer esto otro
Código:
<a href="/compartir?demo"><script>alert(123)</script>=&amp;p=1" title="Mostrar la página anterior">
En tu código php tienes esto
Código:
$url = Servidor::PhpSelfSinExtension() .'?';
$url .= Servidor::PropagarVariblesGet(APP_VAR_REQUEST_NUM_PAGINA_ENLACES);
$url .= APP_VAR_REQUEST_NUM_PAGINA_ENLACES.'=';
$url = Servidor::UrlParaXhtml($url);
Como ves metes todas las variables get sin comprobar si algún listo añadió alguna por su cuenta.

Y en este otro tramo:
Código:
<a href="'.$url.$i.'" title="'._r('Mostrar la página siguiente').'">
Así que aprovecha esto para insertar parámetros de mas en la url, estos parámetros contienen caracteres como < y " que tu insertas directamente en tu pagina. De esta manera cierra la etiqueta del enlace e inserta el código del script.

Cita:
Empezado por dec
¿Hasta qué punto compromete la seguridad esto?
Un script podría hacer que en tu pagina se mostraran cosas que no tienen nada que ver contigo. Con el consiguiente riesgo que esto conlleva. Por ejemplo Cross Site Scripting se utiliza para el phising.
Responder Con Cita
  #6  
Antiguo 04-12-2006
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Vale, todo mi trabajo de detective a la porra ...
Responder Con Cita
  #7  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Para nada Seoane. Ni mucho menos.

Por otro lado la segunda URL es curiosa. Se consigue el mismo efecto escribiendo en la casilla de búsqueda de Loturak: demo" onmouseover=alert(123) "

Al cabo en la página se termina escribiendo el siguiente código:

Código:
<input name="b" value="demo\" onmouseover="alert(123)" \="" id="casillabusqueda" class="inputtext" type="text">
Y el evento, lógicamente, funciona...

Y acabo de confirmar lo que me temía... funciona lo mismo con el resto de casillas de formularios... acabo de probar con el formulario para añadir enlaces y funciona... ¡ay diosito ayúdame!
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #8  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Vale. Pues la segunda cuestión (la que plantea la segunda URL) se me está atragantando. Y es que si en el primer caso podíamos actuar en un mismo punto, en una función en concreto, en este segundo caso no parece que sea así.

He conseguido escapar la cadena de búsqueda (en que se incluye el JavaScript) con la función "htmlentities", de manera que aparentemente se soluciona el tema. Empero, he dicho antes que todas las casillas de los formularios de la aplicación están comprometidas...

Y sólo hay una función que "controle" cada una de estas casillas. El método "Escapar" que hemos visto antes. Sin embargo, aunque pareciera que esto iba a servir de ayuda, en realidad no lo parece. Véase el método "Escapar" tal y como está ahora:

Código PHP:
    function Escapar($cadena) {
        return 
mysql_real_escape_string(stripslashes
         
(strip_tags($cadena)), $this->enlaceConexionBd);
    } 
Pues bien, si lo dejáramos tal que así:

Código PHP:
    function Escapar($cadena) {
        return 
mysql_real_escape_string(stripslashes
         
(strip_tags(htmlentities($cadena))), $this->enlaceConexionBd);
    } 
Funcionaría por un lado, es decir, ya no tendría efecto el JavaScript de las casillas, de las variables que nos llegasen vía "HTTP GET", quiero decir, pero,... ay diosito si es que todo lo hago mal...

Resulta que el mismo método "Escapar" que usamos para las variables que nos llegan de entrada, también lo usamos cuando mostramos la información de dichas variables en las correspondientes casillas.

Me explico. Cuando vamos a mostrar la búsqueda realizada por el usuario escribimos en la casilla de búsqueda la búsqueda actual... o sea, trabalenguajes aparte, hacemos algo como esto:

Código PHP:
$casillaBusqueda $bdatos->Escapar(BUSQUEDA); 
Pero, al hacer esto, pareciera que la función "htmlentities" codificara la cadena que se muestra en la propia casilla, de manera que esta no se muestra bien... creo que una imagen vale más que mil palabras en este caso.

Conseguimos que el JavaScript no tenga efecto, pero, los datos de las casillas se muestran malamente:



Total,... yo llevo creyendo hace tiempo que igual que usamos un método "Escapar" deberíamos utilizar un método "Desescapar"... o que en todo caso no estamos haciendo un buen uso del método "Escapar"... lo usamos un poco sin ton ni son, me parece a mí...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #9  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Bueno. Disculpad mi pesadez, pero, es que me parece curioso, la verdad. Respecto del problema con la segunda de las URLs resulta que no ocurría sólo en las casillas de los formularios... no. Cuando se realiza una búsqueda en la página Web de que hablamos se indica al usuario que los enlaces están filtrados por dicha búsqueda.

Una de las formas en que se indica es haciendo uso de diversos iconos, que tienen un "título", es decir, cuando el usuario pasa el ratón por encima le aparece el típico "hint" que le muestra algo como: "Buscando enlaces por: Delphi". Donde "Delphi" es la cadena que se está buscando.

Pues bien, lo mismo que para las etiquetas, servía para los de los títulos, así que en la medida de lo posible lo estoy corrigiendo, aunque tengo que revisar algunas cosas. Empero,... lo de las casillas... en fin. Seguiremos informando.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #10  
Antiguo 04-12-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
No sé yo si diré una burrada, pero a mi me parece que no hay por qué preocuparse por este segundo tipo de "ataque". Por un lado parece más difícil de evitar porque no intervienen etiquetas html, sólo atributos, pero por otro, me da porque a quien "afecta" es sólamente al que le apetezca colocar tal texto en la caja, pero a nadie más, no al menos mientras esta información no se guarde permanetemente en algún lugar.

// Saludos
Responder Con Cita
  #11  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Qué tarea más ingrata, y, sin embargo, necesaria... lo cierto es que estos problemas no los veía venir, pero, sabía de algún modo que no estaba haciendo las cosas bien. Hablo de utilizar el método "Escapar" para todo...

Llevo desde esta tarde liado con el asunto... son las 5:20 de la mañana... estoy un poco cansado, y además hoy no era el día, no era el día y se nota... El caso es que he conseguido evitar el problema de la segunda URL.

Pero, lo he conseguido a medias aún. Es algo que tengo que seguir revisando, pues se ha visto afectado no poco código fuente de la aplicación, para mi mal. Voy a tratar de ser breve pero espero explicarme. Básicamente ya lo he dicho.

El método "Escapar", concretamente, este método:

Código PHP:
    function Escapar($cadena) {
        return 
mysql_real_escape_string(stripslashes
         
(strip_tags($cadena)), $this->enlaceConexionBd);
    } 
Ha de utilizarse cuando tratamos con consultas en la base de datos. Véase la ayuda de la función "mysql_real_escape_string". Pues bien, aunque en Loturak lo estábamos usando medio bien -entre otras cosas estoy revisando esto también- lo cierto es que usábamos este mismo método para cosas como esta:

Código PHP:
$tituloEnlace $bdatos->Escapar($_POST['enlace-titulo']); 
Y eso es correcto (según empiezo a comprender, que puede que me equivoque) si luego vamos a utilizar la variable "$tituloEnlace" dentro de una consulta SQL. Ojo, que el "Escapar" no es lo mismo que validar la entrada... esto ha de hacerse por otro lado de todas, todas, vamos, si es menester.

Pero, también estábamos usando ese método para mostrar los propios datos de los enlaces en diferentes sitios de la aplicación... es decir, por ejemplo, mostrábamos la variable "tituloEnlace" en una casilla de formulario, pero, no sólo... que no veáis qué odisea, puesto que el problema de la segunda URL, ya sabiéndolo, no se daba sólo en las casillas de los formularios... pero en muchos otros lugares...

Y aquí es donde entreba en juego otro método Escapar... pero no para cadenas a utilizar en consultas SQL, sino para usar tal como vengo diciendo ahora...

Código PHP:
  function Escapar($entrada) {
      return 
htmlentities(strip_tags($entrada), ENT_QUOTES'utf-8');    
  } 
El compañero que me informó de todo este asunto me comentó por correo electrónico que acaso sería posible "juntar" en el método "Escapar" conque contábamos antes lo de antes y el "htmlentities",... pero, aunque esto pudiera haber funcionado, lo cierto es que el compañero olvidaba mi desastrada codificación, pues, como he dicho, estaba usando el método "Escapar" para lo que no debía usarse ni era necesario...

Bien. De mi capote añado que tratándose de consultas SQL no es preciso el "htmlentities", puesto que, como digo, bastaría con escapar las cadenas con "mysql_real_escape_string", "stripslashes" y "strip_tags", como lo hacemos ahora...

En fin. No sé siquiera si llegaré a hacerme entender... la verdad, me desperté hoy con la primera en la frente... ¿recordáis el MD5 de las contraseñas? Pues después de esa taza de caldo otra más... y de qué manera...

Así que creo que voy a dejarlo por hoy, qué coño, que me lo merezco, me parece a mí y ya está bien. Ahora, como digo, aunque aparentemente solucionados los problemas que podían causar las dos URLs indicadas al inicio, comprendo que mañana, si es otro día, me queda no poco trabajo todavía con este asunto...

Bueno. Muchas gracias a todos por vuestra ayuda. Si consideráis que me equivoco en algo me lo hacéis saber con sinceridad, ¿eh? Pues eso.

PD. Román, ciertamente, el grado de "peligro" que pudiera darse con este tema acaso no sea de alarma roja, aunque, me da en la nariz que esto del "Cross Site Scripting" puede ir mucho más allá de mostrar una "alerta" al usuario... el mismo nombre lo puede estar diciendo... pareciera algo peligroso, lógicamente, para alguien que supiera y quisiera explotar algo así.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #12  
Antiguo 04-12-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por dec
PD. Román, ciertamente, el grado de "peligro" que pudiera darse con este tema acaso no sea de alarma roja, aunque, me da en la nariz que esto del "Cross Site Scripting" puede ir mucho más allá de mostrar una "alerta" al usuario... el mismo nombre lo puede estar diciendo... pareciera algo peligroso, lógicamente, para alguien que supiera y quisiera explotar algo así.
Está claro que puede ir mucho más allá de un alert. A lo que me refiero es que quien resultaría afectado sólo sería el mismo que lo puso, es decir, un suicidio.

// Saludos
Responder Con Cita
  #13  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Pues muy bien puedes estar en lo cierto Román. La verdad que es que cada día que pasa estoy más verde en todo, me parece, y en esto del Cross Site Scripting... no es que esté verde,... es que da miedo pánico, precisamente, por lo desconocido que resulta para mí.

Acabo ahora de ponerme "en marcha". Vamos a ver cómo se da el día,... que ha vuelto a empezar como ayer... con una bombilla fundida en mi habitación fruto de un cortocircuito en uno de los casquillos de la lámpara... nadie cuida de estas cosas y estas cosas se estropean con el tiempo...

Vale. Seguimos en contacto.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #14  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Voy a hacer una serie de comentarios, explicar unas cuantas ideas, para ver si alguien puede decir "no, amigo mío, en esto y aquello estás confundido". Se lo agradeceré enormemente, puesto que quisiera que todo esto de que ahora hablaré quedara bien claro en mi cabeza.

La clase en la que me basé para llevar a cabo la clase "BDatos" que vengo utilizando ya contaba con un método "Escapar". Yo nunca hasta hoy (si puede decirse luego se verá) he comprendido el significado de dicho método "Escapar" en la clase BDatos. Por mejor decir nunca lo comprendí en su totalidad.

Yo tenía claro que el método "Escapar" no servía para validar las entradas del usuario. Esto era tarea que había que hacer, convenientemente, por separado. Sin embargo no entendía a qué se dedicaba entonces el método "Escapar", y resulta que este método ha de utilizarse para evitar "ataques" de "SQL Injection".

Hasta hace dos días estaba usando la función "mysql_escape_string", por no mirar con detenimiento en el manual de PHP, pues resulta que esta función se considera "obsoleta" y en su lugar hay que utilizar la función "mysql_real_escape_string". Recordad que con esta función pretenden escaparse determinados caracteres para evitar lo que se conoce como "SQL Injection".

Esto es lo que tenía que haber tenido claro desde un principio y nunca lo tuve hasta hoy. No se trata de "escapar" caracteres para entrarlos a la base de datos o algo parecido... se trata de evitar que una consulta SQL no contenga determinados caracteres...

Cita:
Empezado por Manual de PHP
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a.
Que pueden dar lugar a inyecciones SQL, como vengo diciendo, vamos, y como se dice en el manual de PHP... que yo no leí atentamente ni mucho menos.

Al confundirme yo en ese punto, es decir, al pensar que el método "Escapar" servía para descartar "caracteres peligrosos", así, en general,... y no determinados caracteres de una cadena que luego se usará en una consulta SQL... Y NADA MÁS... como yo estaba equivocado, me puse a utilizar como un loco el método "Escapar"... para casi todo.

Por ejemplo, en la entrada del usuario de un determinado formulario... ¿qué hacía? Escapar los caracteres con el método susomentado. ¿Iba a formar parte la entrada del usuario en una consulta SQL? Ah... unas veces sí, otras veces no... no tenía ningún conocimiento,... mi intención era que en la entrada del usuario no vinieran caracteres "extraños"... y ya está.

Y ya está el lío montado, quiero decir. Porque voy a tener que repasar todo el código de la aplicación, prácticamente, como buenamente pueda, en busca de estas incongruencias.

Y menos mal que al fin y al cabo conocía la diferencia entre la validación de la entrada del usuario y su "escape"... porque lo segundo puede sobrar, pero, lo primero es imprescindible y no sólo por cuestiones de seguridad, sino también porque así lo exige la propia aplicación... por ejemplo, la descripción de un enlace no ha de contener más de X caracteres y esto hay que validarlo. ¡Pero no hay que escaparlo siempre!

Hay que "escaparlo" con el método "Escapar" de la clase "BDatos" cuando dicha descripción va a formar parte de una consulta SQL... entonces sí, pero, si no es así, si únicamente va a presentarse dicha descripción en la página Web, entonces el "escape" se hace innecesario... a lo menos es "escape" que trata de evitar el "SQL Injection"... ¿Cómo iba a darse un ataque de este tipo si no se va a llevar a cabo consulta SQL ninguna?

Y aquí es donde entramos en el "Cross Site Scripting." Es decir, la cadena que vamos a validar no se incluirá en ninguna consulta SQL, pero, sí se mostrará en la página Web... código HTML... al fin y al cabo... al que se le pueden añadir "cosas" como un evento que se dispararse cuando se pasar por encima de determinado elemento. Es decir, justo lo que el compañero que me escribió amablemente para darme luz sobre todo esto propuso en la segunda URL de ejemplo que hay al comienzo de este Hilo.

Es aquí, amigos, donde entra el "Escape" necesario, que esta vez no tiene que ver con el uso de la función "mysql_real_escape_string"... sino con la función "htmlentities", por ejemplo, junto con "strip_tags", si se me apura, o a lo que yo entiendo. Lo que pretendemos al hacer uso de esta función es evitar las posibles etiquetas PHP y HTML (?) que se incluya en la entrada del usuario, así como convertir determinados caracteres en sus correspondientes entidades HTML.

Bien. Ya termino. Os pido disculpas por el rollo. Si habéis leído hasta aquí ya tenéis valor, ya.

Este es el método "Escapar" conque ahora cuenta la clase "BDatos":

Código PHP:
    function Escapar($cadena) {
      
// http://es.php.net/manual/en/function.mysql-real-escape-string.php
      
if(get_magic_quotes_gpc()) $cadena stripslashes($cadena);        
        return 
mysql_real_escape_string($cadena$this->enlaceConexionBd);
    } 
Y este es el método "Escapar" conque ahora cuenta la clase "XHtml":

Código PHP:
  function Escapar($entrada) {
      return 
htmlentities(strip_tags($entrada), ENT_QUOTES'utf-8');    
  } 
Si tenéis algo que decir sobre ellos soy todo ojos. El trabajo que me queda ahora es revisar lo necesario para que dichos métodos se utilizen donde convengan y no donde no convengan. Voy a ver si no cuesta tanto como me parece que va a costar... porque sigo estando bicho, bicho, bicho. O algo peor.

Bueno. No digo nada. Agur.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #15  
Antiguo 04-12-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Pues a mi me parece un estupendo resumen. Si lo sacas un poco de contexto (es decir, quitas las referencias a un proyecto en particular) me parece ideal para aparecer en la sección de trucos del Club. Estas inyecciones son algo que todos deberíamos evitar y que sin embargo muy pocos sabemos no ya como hacerlo, sino de su misma existencia.

// Saludos
Responder Con Cita
  #16  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Yo creo que me ha quedado como el culo... Y la verdad es que no tengo todo demasiado claro... de hecho sigo trabajando en esta cuestión... y lo que te rondaré morena. Seguiremos informando. Gracias Román.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #17  
Antiguo 04-12-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Creo que hay un problemita dec. Digamos que tu consulta es

Código SQL [-]
select * from usuarios where usuario = 'pepe el toro'

Al aplicarle la función Escapar queda así:

Código SQL [-]
select * from usuarios where usuario=\'pepe el toro\'

Y esto no lo acepta MySql.

// Saludos
Responder Con Cita
  #18  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

No. En realidad no se le aplica "Escapar" a la consulta SQL, sino a los elementos que la conforman.

Es decir, no se hace algo como esto:

Código PHP:
$titulo $_POST['titulo'];
$consultaSql Escapar("SELECT * FROM enlaces WHERE titulo = '$titulo'"); 
Sino que se hace algo como esto otro:

Código PHP:
$titulo Escapar($_POST['titulo']);
$consultaSql Escapar("SELECT * FROM enlaces WHERE titulo = '$titulo'"); 
Sigo el manual de PHP, la función: mysql_real_escape_string, concretamente el ejemplo número 2: "An example SQL Injection Attack".
__________________
David Esperalta
www.decsoftutils.com

Última edición por dec fecha: 04-12-2006 a las 19:15:36.
Responder Con Cita
  #19  
Antiguo 04-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Por cierto, el método "Escapar" de la clase XHtml va por estos derroteros por el momento...

Código PHP:
  function Escapar($entrada) {
      return 
htmlentities(strip_tags
       
(stripslashes($entrada)), ENT_QUOTES'utf-8');    
  } 
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #20  
Antiguo 05-12-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Bueno... pues ya estoy más tranquilo (acabo de suspirar y todo, no te digo yo que...). Menudo repaso le he pegado al asunto (léase Loturak - ¡ajá!). Lo bueno y lo malo de estas cosas es que no ves errores que los tienes ahí en tus narices... y que luego aparecen como por arte de magia. He solucionado no pocos errores o potenciales problemas (¿los llamaré "bugs"?) mientras andaba con el tema de los "escapes"...

Por otro lado creo que me ha quedado claro para siempre lo que he comentado más arriba: una cosa es el "escape" por el que tiene que pasar variable que luego tiene que pasar por una consulta SQL, y otra cosa es el "escape" que tiene que pasar una variable que luego imprimiremos en el código HTML de la página Web de turno. Si hubiera estado con más proyectos además de Loturak estoy seguro de que el problema se hubiera producido en todos ellos.


El "escape" de variables para consultas SQL

Supongamos algo como esto:

Código PHP:
 
 $titulo 
'';
 if(isset(
$_GET['titulo']))
   
$titulo $_GET['titulo'];
 
 
$consultaSql "SELECT * FROM enlaces WHERE titulo = '$titulo';"
Lo que entiendo ahora como correcto queda tal que así:

Código PHP:
 
 $titulo 
'';
 if(isset(
$_GET['titulo']))
   
$titulo $bdatos->Escapar($_GET['titulo']);
 
 
$consultaSql "SELECT * FROM enlaces WHERE titulo = '$titulo';"
Y el método "Escapar" utilizado es:

Código PHP:

function Escapar($cadena) {
  if(
get_magic_quotes_gpc()) $cadena stripslashes($cadena);        
    return 
mysql_real_escape_string($cadena$this->enlaceConexionBd);

Con eso, según el manual de PHP estamos evitando un posible "ataque SQL Injection" de esos... que haberlos haylos, que me lo han dicho a mí.

No sigo el manual al dedillo en mi caso, puesto que según se dice en el mismo "la mejor forma de hacer esto es":

Código PHP:
function quote_smart($value)
{
    
// Stripslashes
    
if (get_magic_quotes_gpc()) {
        
$value stripslashes($value);
    }
    
// Quote if not a number or a numeric string
    
if (!is_numeric($value)) {
        
$value "'" mysql_real_escape_string($value) . "'";
    }
    return 
$value;

Es muy probable que acabe utilizando algo así. Si no lo hago ahora es porque las consultas SQL acostumbro a realizarlas incluyendo por mi cuenta las comillas "simples" para valores de tipo "cadena" y no incluirlas para valores de tipo numérico: por lo demás, ambos métodos de escape son iguales. De hecho yo me copié del manual.

Nótese, sin embargo, que el método de escape no valida la entrada del usuario, es decir, se limita a escapar determinados caracteres para impedir el SQL Injection. Para validar la entrada del usuario debemos contar con las correspondientes reglas, que tendremos que aplicar por nuestra cuenta. Es decir, el código anterior quedaría algo así:


Código PHP:
  
  $titulo 
'';
  if(isset(
$_GET['titulo']))
    
$titulo $bdatos->Escapar($_GET['titulo']);
  
if(!
ValidarTitulo($titulo))
{
  
MostrarError();  
  die;
}
else
{
  
$consultaSql "SELECT * FROM enlaces WHERE titulo = '$titulo';";
  
EjecutarConsulta($consultaSql);
  } 
Pero creo que puede verse más claro de este modo:

Código PHP:
   
   $titulo 
'';
   if(isset(
$_GET['titulo']))
     
$titulo $bdatos->Escapar($_GET['titulo']);
   
 if(!
ValidarTitulo($titulo))
 {
   
MostrarError();  
   die;
 }
 else
 {
   
$consultaSql "INSERT INTO enlaces (titulo) VALUES('$titulo');";
   
EjecutarConsulta($consultaSql);
   } 
Es decir, no aceptaremos en la base de datos enlaces que no cumplan determinadas reglas, sea que miremos por la longitud (en caracteres) del título, sea que reviremos que no contenga determinados caracteres, etc.

Así que como puede verse una cosa no excluye a la otra. Se escapan las variables que van a entrar a formar parte de una consulta SQL. Se valida la entrada del usuario siguiendo las reglas que consideremos oportunas. No son cosas iguales... aunque a mí me lo pareciera hasta anteayer.


El "escape" de variables que van a imprimirse en el HTML

Este tema es curioso. O a mí me lo parece, vamos. Ya visteis cómo la segunda URL que puso el compañero que informó del problema en Loturak conseguía introducir un "evento JavaScript" en un determinado elemento HTML.

Lo que más me llamó la atención (aunque no intuía aún la posible solución) es que el "problema" no se daba sólo con la URL que el compañero propuso, sino que ocurría también en todas las casillas de todos los formularios de la aplicación...

Más tarde descubrí que ni siquiera eso... el problema se daba en más sitios que en las casillas de los formularios, pero, en ambos casos estábamos hablando de lo mismo.

Cuando nos llegan variables vía GET, por ejemplo, y estas van a imprimirse en el código HTML de la página Web también hay que "escaparlas", pues, aunque ya sabemos que no estamos hablando del mismo tipo de "escape" que arriba comentamos para las consultas SQL.

Código PHP:

function Escapar($entrada
{
  return 
htmlentities(strip_tags
   
(stripslashes($entrada)), 
    
ENT_QUOTES'utf-8');    

El "atacante" puede hacer virgerías... así que aplicamos determinados filtros a la entrada (del usuario) para tratar de "paliar" las consecuencias o eliminarlas del todo... si se puede.

Con las funciones de que se compone nuestra función "Escapar" tratamos de convertir algunos caracteres especiales de HTML a su entidad correspondiente. Por ejemplo, sustituimos los "&" por "&amp;". A continuación eliminamos de la variable "entrada" las etiquetas HTML y PHP que pudiera contener. Y para terminar eliminamos los "\" de la entrada.

Todo esto para evitar, por ejemplo, que recibamos en una variable de entrada algo como esto:

Código:
demo" onmouseover=alert(123) "
Si no escapáramos esa entrada y la misma terminara imprimiéndose tal cual en el código HTML de la página Web tendríamos algo como esto:

Código:
<input name="b" value="demo\" onmouseover=alert(123) \"" type="text" id="casillabusqueda" class="inputtext" />
Es decir, que cuando el usuario pasara el ratón por la casilla de búsqueda, en este caso, iba a recibir un pequeño susto....

¿Qué ocurre cuando se escapa la cadena de entrada con el método anteriormente visto? Algo bastante distinto, gracias, en este caso más que nada, a la función "htmlentities":

Código:
<input name="b" value="demo&quot; onmouseover=alert(123) "" id="casillabusqueda" class="inputtext" type="text">
De ese modo le mostramos al usuario lo que realmente ha buscado... pero, principalmente impedimos que el evento que trataba de introducirse surta efecto alguno.

Ahora bien. Lo curioso del asunto es que este tipo de escape no se ciñe sólo variables que nos llegan vía HTTP GET, por ejemplo. Supongamos una aplicación que permita a sus usuarios guardar datos de sus enlaces favoritos (¡ajá!).

Supongamos que alguien introduce como título de un enlace la cadena anterior. Puede que sea válida, es decir, puede que la aplicación considere que esa cadena resulta válida como título de un enlace: cumple con las reglas.

Pero, en cuanto esa cadena se introduzca como título de un enlace tendremos el problema multiplicado por la aplicación... en todo lugar en que se muestre el enlace del usuario puede terminar ocurriendo que "el evento JavScript" funcione... no sólo en las casillas de los formularios, sino en cualquier otra parte.

Precisamente, en cualquier otra parte en que se muestre el título del enlace... porque lo mismo da esto:

Código:
<input name="b" value="demo\" onmouseover=alert(123) \"" type="text" id="casillabusqueda" class="inputtext" />
Que esto otro:

Código:
<li name="b" title="demo\" onmouseover=alert(123) \"" />
El evento se añadirá esta vez en la lista en la que mostramos una serie de enlaces, por ejemplo. Como cada elemento de la lista muestra el título del enlace y el título del enlace contiene el "código malicioso"... pues eso.

Es decir, ya no recibimos la cadena "peligrosa" y a escapar desde la entrada del usuario, bueno, sí, pero, esta puede estar ya en nuestra base de datos... porque, como he dicho, la cadena anterior puede ser válida como título de un enlace y será guardada en la base de datos religiosamente... y cada vez que la precisemos mostrar en el código HTML de la aplicación tendremos problemas...

Mejor dicho tendríamos problemas. Y es que si procuramos escapar este tipo de variables con la función de más arriba, aparentemente, al menos, se acabaron las disputas en ese sentido al menos.

No es que haya que escapar todos los datos de un enlace (siguiendo con el ejemplo, para hacerme entender). Por ejemplo, si en nuestra tabla de enlaces guardamos el ID, el título y la URL de un enlace,... lo que puede resultar "peligroso" es el título y la URL, precisamente, porque es el usuario quien determina el título y la URL de los enlaces. Como el ID es un dato en el que no interviene el usuario no es necesario que lo escapemos. Y quien dice el ID dice la fecha del enlace, el número de visitas, etc., cualquier dato que el usuario no pueda editar.


Conclusiones

Dicho todo esto, se entenderá porqué tenía los problemas que tenía en la Web que me traigo entre manos: estaba utilizando el mismo método "Escapar" para todo... entradas de usuario, datos de la base de datos, variables para consultas SQL... para todo usaba el mismo método, además no del todo en condiciones... ¿cómo iba a ir la cosa? Pues mal.

Así que agradezco un montón a quien se molestó en informarme de este problema. Creo que me ha quedado lo suficientemente claro el asunto como para andarme con ojo en la aplicación de aquí en adelante y saber por dónde ando en este sentido. Muchas gracias también a todos cuantos colaborásteis de algún modo.

Y ya está. Eso es todo. Disculpad el rollo, y, si tenéis cualquier cosa que decir respecto a lo dicho aquí no dejéis de hacerlo, por favor. Cualquier comentario, sugerencia, crítica, correción, todo será bienvenido.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Pivot table Editable (cross-tab) villegasmajano MS SQL Server 1 25-10-2006 23:28:57
como manejan uds en Firebird 1.5 el PIVOT de oracle?? (CROSS TABS) pvizcay Firebird e Interbase 4 19-09-2006 19:17:32
Ajuste de decimales en un Cross-Tab nugame Impresión 4 16-06-2004 13:40:44


La franja horaria es GMT +2. Ahora son las 20:54:02.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi