TallerPHP: Se inició el primer contacto con los líderes de los equipos

Sepan disculpar mi demora con el avance del taller, pero se han suscitado muchos compromisos juntos que me han dejado poco tiempo libre.

Pero bueno, más real no puede ser el taller, ¿cuando han visto un Gerente que no esté ocupado y que sobrecargue a sus "Team Leaders"? ;-)

Como habrán visto en la planilla, cada líder tendrá 2 misiones: desarrollar un sistema particular y desarrollar un sistema en conjunto con los demás equipos.

Por consiguiente, empezaremos con el proyecto común para iniciar el trabajo en equipo, definir la comunicación entre nosotros y posteriormente la asignación de tareas de cada uno de sus recursos (desarrolladores).

"Clases Base"

La idea es desarrollar una estructura base de clases como cuentan en el lenguaje Java: clase Array, String, Integer, etc. Cada líder irá tomando un conjunto de clases y asignará a sus recursos una para desarrollar. Puede ser una clase entera, o compartir con ellos el desarrollo parcial de cada parte (un método cada uno).

Donde tomaremos las clases es en www.gotapi.com, sección J2SE 1.5 (especificación del lenguaje Java) y navegando en el arbol (izquierda): java.lang

De ahí (documentación de la API) sacaremos la estructura base de cada clase. Antes de iniciar cualquier desarrollo debemos estar coordinados entre los líderes y su gerente de proyectos.

Está demás decir que los desarrolladores de cada equipo vayan "calentando los motores", pues en poco días recibirán el llamado para unirse a las filas.

Los escucho: ¿preguntas, dudas, crisis? ;-)

Taller: Ya se encuentran armados los equipos de desarrollo



Espartanos, desayunad bien. ¡Porque esta noche cenaremos en el infierno!

Mil disculpas a todo el mundo, pero la verdad que me he envuelto en muchos compromisos que me han quitado tiempo para dedicarme a terminar de definir el taller. Por suerte, luego de analizarlo varios días tengo ya pronto los equipos de desarrollo con cada uno de sus integrantes.

Están creados los foros en Google Groups, existe uno privado exclusivo para los líderes (donde impartiré las órdenes y las sugerencias para gestionar sus equipos) y luego uno para cada equipo así pueden trabajar con su líder.

Se encuentra una planilla pública donde se puede visualizar la lista de grupos e integrantes y los sistemas que se deberán desarrollar.

En las próximas horas me estoy comunicando con cada líder para empezar a trabajar en los requerimientos de los sistemas.

¡Bienvenidos, seguimos con la segunda parte del Taller Piloto de PHP5!

Solución Semana 4: "Sistema Modular" (V de V)

El punto V de los requerimientos de la Semana 4 decía:

Seguridad: el sistema actual confía de los datos que recibe, lo cual puede convertirse en un problema de seguridad a través de un ataque del tipo "sql injection". Proponer una solución a este problema.

En el propio manual oficial de PHP hay un capítulo exclusivo sobre Seguridad (IV) y dentro existe una sección sobre Bases de Datos y una sub-sección que dice concretamente Inyección de SQL:

La Inyección Directa de Comandos SQL es una técnica en la cual un atacante crea o altera comandos SQL existentes para exponer datos escondidos, o sobrescribir datos críticos, o incluso ejecutar comandos del sistema peligrosos en la máquina en donde se encuentra la base de datos. Esto se consigue cuando la aplicación toma información de entrada del usuario y la combina con parámetros estáticos para construir una consulta SQL. Los siguientes ejemplos, desafortunadamente, están basados en historias reales.

Esta parte la vivimos la comienzo de la puesta en producción del sistema de registro de usuarios para este taller piloto de PHP5, donde uno o más saboteadores intentaron borrar la base de datos usando este tipo de ataque.

Veamos qué podemos hacer para reforzar la seguridad

La esencia es evitar completamente que los datos lleguen en bruto desde la url o de un formulario hacia la base de datos, verificando cada dato y asegurando que la construcción final del SQL no sea alterada para modificar el funcionamiento normal de nuestro sistema.

La lista a continuación no es extensa, solo intenta ser una introducción al tema:

  1. Verificar los tipos de datos que se reciben: controlar cada uno de los parámetros según el tipo de dato que se espera. Si es un campo numérico del formulario se deberá verificar que sus datos sean así, numéricos, evitando que agreguen una cadena de texto (String) con código SQL maligno.
  2. "Escapear" caracteres riesgosos: comilla simple ('), comilla doble ("), barra invertida (\) y NULL (el byte NULL). Hay que tener en cuenta que si los datos son grabados en la base de datos con "caracteres escapeados" (addslashes), hay que hacer el proceso inverso para presentarlos en pantalla (quitando las "\" con stripslashes).
  3. Agregar procesos que verifiquen sentencias SQL: otra forma de reforzar es verificar que cada cadena de texto que debamos ejecutar en la base no contenga determinadas palabras que no estamos usando para una determinada operación. Por ejemplo, si deseamos obtener datos sin modificar la base (SELECT) no deberíamos permitir que se ejecutaran comandos como "INSERT", "DELETE" y "UPDATE" (ni ningún otro que permita saber información interna ni de las estructuras de las tablas), y/o directamente prohibir que se puedan agregar "AND", "OR" o un ";" (lo que permite agregar a continuación otra sentencia SQL).
Estimo que la mejor forma de tener controlado este proceso es separar los datos por un lado, la generación de las consultas SQL por otro, y evitar tener un proceso genérico donde todo pase por el mismo lugar.

Algunos ejemplos

Nota: si la imagen no se visualiza claramente, presionar sobre ella para ampliarla.


Validar el tipo de valor que recibo por parámetros: para luego pasarlo al armado de la consulta.

En este caso esperamos que los valores posibles son Null o un Integer, si es el primero hacemos un "SELECT * FROM usuarios" y si es el segundo esperamos que sea un número de usuario. Verificamos que no sea nulo, y luego nos aseguramos que sea un valor numérico.

Crear un método "quote" en la clase BaseDeDatos:
el término quote se usa en muchos frameworks a la hora de crear un proceso que "escapee" (si alguien conoce castellanización que avise) las variables que se usan en una sentencia SQL.

En este caso verificamos la existencia de funciones que ya realizan automáticamente el "escaping", de lo contrario lo hacemos manualmente. De la misma forma existe una función de PHP específica para la base MySQL, lo cual nos ataría a futuro si queremos cambiar de base de datos.

Separar los datos de la consulta sql:
para poder procesar fácilmente cada dato.


En este caso tomamos nuestro método ejecutarSQL, que solo recibía una sentencia sql, y que ahora recibe por un lado el esqueleto de la sentencia y por otro los valores a ser insertados en la construcción de la sentencia final. Su funcionamiento es similar al de cualquier sistema de templates.


Aquí pasamos por referencia (&) la sentencia original para modificarla, sustituyendo nosotros cada uno de los valores en los lugares que corresponde insertar y ejecutando la "sanitización" de cada valor con el método "quote".


Nuevamente la definición del método "quote".

Este es un ejemplo de cómo funcionaría en una situación donde queremos solo obtener datos de la base de datos, definiendo primero un array de datos asociando la clave PAR01 (parámetro 1) y el valor recibido por la url. Luego, se armar el template SQL y colocando el PAR01 donde debería ir para que el proceso de armado sustituya de forma segura por el valor correspondiente luego de "desinfectarlo".

Este es otro caso, el más complejo, donde hay alteración de la base de datos y existe más de un parámetro. La lógica es simple, y como afirmé más arriba, es lo mismo que utilizar un sistema de templates o plantillas, defines una marca o variable que será sustituida por el valor que tu asignes, manteniendo el resto sin alterar.

Validación con Javascript


Finalmente, no quiero olvidarme comentar el tema de las validaciones desde el propio cliente con Javascript (lo vi comentado en una de las soluciones entregadas por algunos participantes del taller). La solución de este lado del proceso puede considerarse un complemento, pero no la solución más segura. Estimo que cualquier usuario que quiera hacer un ataque de este tipo lo primero que probará si encuentra controles del lado del cliente es deshabilitar el Javascript en el navegador. Sirve como complemento, pero no es la mejor opción ni la más segura.

La recomendación final

El tema de la seguridad es una tarea muy especializada, no sirve agregar un par de métodos con algunas funciones, habría que auditar constantemente todo el código nuevo que se agrega al sistema. Para este caso particular, el SQL Injection, como afecta exclusivamente a la persistencia de datos en un motor de base de datos, lo mejor es tener una "capa de abstracción" de terceros que tenga bien resuelta toda esta problemática. Por ejemplo, podemos usar MDB2 del framework Pear o directamente PDO que incorpora el propio PHP5.1 en adelante.

Documentación relacionada
Ya se encuentra la planilla actualizada, como así también el repositorio con los fuentes y como siempre, en los comentarios de esta entrada se pueden sacar las dudas sobre este tema :-)

PD: en las próximas horas se estarán haciendo los anuncios con los equipos de desarrollo armados. En primera instancia estarán involucrados los participantes que sobrevivieron todo el proceso del taller (¡Felicitaciones! ;-)) y posteriormente iré analizando la incorporación de más colaboradores en base a la evolución de las primeras pruebas y teniendo en cuenta la lista de registrados al taller.

¡POR FIN, CERRAMOS LA SEMANA 4!

Inciamos hoy el curso presencial de Desarrollo de Sistemas Web con PHP5 (Universidad ORT)

Nota: sigue estando el nombre antiguo de "Programación de Páginas Web con PHP", debería ser Desarrollo de Sistemas Web con PHP5

Menú del día:
  • Acreditación del Docente
  • Presentación del curso
  • Encuesta a los alumnos
  • Introducción a la Web 2.0
  • Conceptos sobre el entorno Web
¡No te lo pierdas, 4 meses intensivos! ;-)

Solución Semana 4: "Sistema Modular" (IV de V)

El requerimiento número 4 correspondiente a la Semana 4 de Taller decía:

Mejorar la búsqueda: corregir la búsqueda por nombre y descripción para que pueda obtener más de una coincidencia (actualmente solo trae una).

En esta situación se podían discutir dos alternativas.
El sistema originalmente iniciaba el formulario de consultas y procedía a ejecutar posteriormente el módulo "mostrar_usuario". Conceptualmente este módulo sirve para eso, para mostrar un usuario, lo cual nos podía llevar a modificarlo para que permitiera mostrar más de uno, ya que el requerimiento así lo especifica.

La segunda alternativa era sustituir la invocación del módulo actual por el "listado_usuarios", ya que la implementación existente tiene todas las características solicitadas: poder mostrar más de un usuario pero agregando ahora parámetros de filtros de búsqueda. De esta forma, una vez generada la lista de usuarios encontrados se podría seleccionar el correspondiente para visualizar la ficha completa del mismo.

En este caso lo ideal sería esta última opción.

Los fuentes afectados fueron:
  • index.php
  • dominio/DominioFachada.class.php
  • persistencia/PersistenciaFachada.class.php
  • persentacion/ListadoUsuarios.class.php
  • persentacion/PresentaciónFachada.class.php
Y los templates afectados fueron:
  • contenido_consultar_usuario.tpl.html
  • contenido_listado_usuarios.tpl.html
Fundamentalmente se agregó que el listado de usuarios pudiera recibir por parámetros filtros de búsqueda ($request), lo que luego de cruzar todas las capas correspondientes se termina recreando consultas SQL que permiten incorporar estas condiciones.

PersistenciaFachada.class.php

public function traerUsuarios( $request = null ){
require_once(
FWK . DIRECTORY_SEPARATOR . "SentenciaSQL.class.php");
$SentenciaSQL = new SentenciaSQL();

// Consulta base
$SentenciaSQL->addSelect("*");
$SentenciaSQL->addFrom("usuarios");

if( (
$request['id'] != "" ) ){
$SentenciaSQL->addWhere("id = ".$request['id']);
}
if( (
$request['nombre'] != "" ) ){
$SentenciaSQL->addWhere(" nombre LIKE '%".$request['nombre']."%'");
}
if( (
$request['descripcion'] != "" ) ){
$SentenciaSQL->addWhere(" descripcion LIKE '%".$request['descripcion']."%'");
}
return
self::ejecutarSQL( $SentenciaSQL->generar() );
}

Aquí lo único que hace es armar la consulta en base a si viene cargado o no cada parámetro que corresponde con las condiciones de filtro de la consulta SQL.

Ya se encuentra la planilla actualizada, como así también el repositorio con los fuentes y como siempre, en los comentarios de esta entrada se pueden sacar las dudas sobre este tema :-)

Entradas populares