Posts from May 2008

SQL Injection, PHP y Bases de Datos

22 May, 2008 | Comentarios (0)

SQL Injection, la temida dirían algunos y la verdad es que si no tienes cuidado al programar suelen ser verdaderos quebraderos de cabeza, que ciertamente despues de retomar código es un tanto dificil de depurar si no sabes lo que ha sucedido.
Aquí voy a relatar modos de tratar ataques SQL Injection, que harán nuestras apps más seguras y a nosotros estár más tranquilos.
Las SQL Injections son consultas sql que son generadas por scripts/programas que concatenan entradas del usuario con consultas a bases de datos, y ahí es donde está el problema ya que no toda la entrada que proporciona el usuario es segura.
Por ejemplo consideremos la siguiente instrucción:

  1. SELECT * FROM users WHERE user = ‘Pepito’

Si quieres en este momento recoger una fila de la base de datos con información del usuario insertada debes reemplazar “Pepito” con la cadena proporcionada por el usuario.
En PHP se vé tal que así:

  1. SELECT * FROM users WHERE user = ‘$_GET[nombreUsuario]‘

El problema es simple: si el usuario inserta una cadena formateada especialmente como el nombre de usuario el puede modificar tu consulta para ejecutar lo que el desee.

Por ejemplo si inserta esto:

  1. ‘;DROP TABLE users;–

Ahora la consulta se verá así:

  1. SELECT * FROM users WHERE user = ;DROP TABLE users;–’

Hay varias formas con las que alguien puede atacar nuestra base de datos mediante sql injection. Las más rudimentarias son escapar los caracteres ‘, pero no siempre funcionan correctamente ya que hay otras formas de alterar la consulta. Echemos un vistazo a esto.

Hay una solucion muy simple a este problema. No concatenes texto proporcionado por el usuario en una consulta, vinculalo. La mayoría de las bases de datos soportan bindings, mysql es una de ellas, postgresql, oracle y la lista crece. La idea es simple: proporcionas un marcador en tu consulta que será reemplazado con la variable actual, por lo que no es posible ninguna modificación posible.

Nuestra anterior consulta se puede escribir tal que así:
Mysql (en php con la extensión mysqli)

  1. SELECT * FROM users WHERE user = ?

Oracle

  1. SELECT * FROM users WHERE user = :user

Ejemplo de la extensión mysqli PHP (para más información lee la función de mysqli_stmt bind_param

  1. /* recoger los datos del usuario */
  2. $nombreUsuario = $_GET[‘nombreUsuario’];
  3. /* preparar la consulta */
  4. $stmt = $mysqli->prepare(‘SELECT * FROM users WHERE user = ?’);
  5. /* vincular el valor */
  6. $stmt->bind_param(’s’, $nombreUsuario);
  7. /* ejecutar la declaración preparada */
  8. $stmt->execute();
  9.  
  10. $stmt->bind_result($name, $surname);
  11. /* recoger los datos de usuario*/
  12. while ($stmt->fetch())
  13. {
  14.   //imprimir los datos del usuario
  15.   echo $nombre, ‘ =>  ’, $apellido , "\n";
  16. }
  17. /* cerrar la operación */
  18. $stmt->close();

Ejemplo con la extensión PHP PDO (para más información lee la función prepare de PDO

  1. /* recoger los datos del usuario */
  2. $nombreUsuario = $_GET[‘nombreUsuario’];
  3. /* preparar la consulta */
  4. $sth = $dbh->prepare(‘SELECT * FROM users WHERE user = ?’);
  5. /* vincultar y ejecutar la consulta */
  6. $sth->execute($userName);
  7. $row = $sth->fetchAll();

Por lo tanto es muy facil para nosotros evitar la reescritura evitando que concatenar los datos proporcionados por el usuario con nuestra consulta, pero hay escenarios donde debes generar una consulta con los datos del usuario, no solo enviando una consulta. Por ejemplo, quieres mostrar diferentes tipos de libros basados en lo que inserta el usuario. El usuario puede elegir ver libros de ciencia ficción, literatura o libros de cocina.

Podrías estar tentado a escribir algo como esto:

  1. SELECT * FROM $_GET[categoriaLibro]

¿Pero, que pasa si el usuario quiere modificar tu script e inserta ‘users’ como una categoría? En ese caso podrá ver el contenido de la tabla de usuarios. La solución para este problema es comprobar la categoría proporcionada por el usuario en vez de la cadena directamente.

En php deberías hacer algo como esto:

  1. switch ($_GET[‘bookCategory’])
  2. {
  3.         case ’sf_books’:
  4.                 $table = ’sf_books’;
  5.                 break;
  6.         case ‘literature_books’:
  7.                 $table = ‘literature_books’;
  8.                 break;
  9.         default:
  10.                 $table = ‘cooking_books’;
  11. }
  12. $query = "SELECT * FROM $table";

Si escribes tu script de esta forma, cuando el usuario inserte ‘users’ como una categoría, el verá los libros de cocina, o puedes elegir mostrar un error, esa es tu elección.
Para resumir este post, quiero decir que deberías utilizar el binding de variables cuando quieras enviar datos a la base de datos que proporciona el usuario. Y si formas tus consultas según la entrada de usuario, simpre compara lo que inserta con algun valor predefinido y usa el valor por defecto.
Nunca concatenes entrada de usuario en tus consultas, sin excepciones

Archivado en... General URI

Configuración de VirtualHosts en Nginx (Nginx II)

8 May, 2008 | Comentarios (0)

Echa la compilación de nuestro nginx ahora voy a explicar mas o menos mi sistema para gestionar virtualhosts con nginx. Primero de todo, suelo meter los virtualhosts en /opt en el que crearemos el esqueleto para cada slice.

Configuramos nginx para virtualhosts utilizando ficheros separados para cada uno de ellos:

mkdir -p /usr/local/nginx/conf/{sites-available,sites-enabled}

Substituímos con lo siguiente en el fichero /usr/local/nginx/conf/nginx.conf, para que lea todos los ficheros en sites-enabled y de paso lo limpiamos:

  1. user www-data;
  2. worker_processes  1; #Número de workers configurable según necesidades
  3.  
  4. error_log  /var/log/nginx/error.log;
  5. pid        /var/run/nginx.pid;
  6.  
  7. events {
  8.     worker_connections  1024;
  9. }
  10.  
  11. http {
  12.     include       /etc/nginx/mime.types;
  13.     default_type  application/octet-stream;
  14.  
  15.     access_log  /var/log/nginx/access.log;
  16.  
  17.     sendfile        on;
  18.     #tcp_nopush     on;
  19.  
  20.     #keepalive_timeout  0;
  21.     keepalive_timeout  65;
  22.     tcp_nodelay        on;
  23.  
  24.     gzip  on;
  25.  
  26.     include /etc/nginx/sites-enabled/*;
  27.  
  28. }
  29.  

LLegados a este punto ya tenemos nuestro nginx preparado para servir cualquiera de los distintos tipos de servidores que soporta (web, proxy web inverso, mail, balanceo de carga). Como aquí nos centraremos en configurar un servidor web con virtualhosts, sigo relatando las operaciones.

Leer más →

Archivado en... Programación, Servidores, Software, Vida virtual, Web URI

Web Server optimizado con Nginx (Nginx I)

7 May, 2008 | Comentarios (1)

Este post inicia una serie de post sobre Nginx, instalación, configuración y optimización todo fruto de el trasteo, la búsqueda de la máxima optimización, en parte impulsada por la limitación de recursos en general de el servidor en el que tengo alojada este humilde site.
En mi incursión en optimizar tanto el rendimiento como el consumo de memoria en mi servidor casero he estado probando Nginx. Despues de muchas pruebas y de escuchar en la red que era el mejor servidor.

Pero vayamos y echemos un ojo a todo de esta maravilla rusa. Nginx (”engine x”) es un servidor HTTP y proxy inverso de alto rendimiento, y un servidor proxy para IMAP/POP3/SMTP. Nginx fue desarrollado por Igor Sysoev para Rambler.ru, el segundo sitio web más visitado de Rusia, donde ha estado, y sigue, funcionando en producción más de dos años y medio. Igor ha lanzado el código fuente bajo una licencia estilo BSD. Nginx es conocido por su estabilidad, gran conjunto de características, configuración simple, y bajo consumo de recursos.
Nginx en estos momentos está haciendo mucho ruído precisamente porque para el caso de montar servidores web es muy rápido, sino el mejor, sirviendo estáticos, esto sumado a la posibilidad de configurar servidores proxy web inversos, nos permite tener un servidor con un rendimiento increíble y lo más importante y lo que más me impactó, en sólo 4 mben runtime.

Nginx es usualmente utilizado como reemplazo de apache que gestiona muchas conexiones concurrentes, como servidor proxy de balanceo de carga, como servidor proxy de mail, entre otros.

Dejemonos de alabanzas y procedamos a la instalación del mismo: En el momento que escribo tanto Debian Testing como Sid tienen unas versiones desfasadas  tiene nginx en su repositorio pero es una versión algo desfasada, 0.4.13, por lo que vamos a compilar e instalar la última versión:

Antes de nada instalaremos unas cuantas dependencias:

sudo aptitude install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev

Hecho esto, ahora procedemos a recoger los fuentes, compilar y configurar.
Leer más →

Archivado en... Linux, Servidores, Software, Vida virtual, Web URI

Autotest con advertencias en Growl

7 May, 2008 | Comentarios (1)

He buscado en la red un método para “enganchar” la utilidad de testeo Autotest en Ruby y el sistema de mensajes de sistema Growl en Mac OS X y la verdad es que no me fue muy bien.
Una vez modificado el archivo .autotest en mi $home ya funciona a la perfección. Relato a continuación como obtener esta maravilla.
Basta instalar Growl en Mac OS tal que así:
wget http://growl.info/files/Growl-1.1.2.dmg
open Growl-1.1.2.dmg
cd /Volumes/Growl\ 1.1.2/Extras/growlnotify
less install.sh
sudo ./install.sh
cd
hdiutil detach /Volumes/Growl\ 1.1.2

y luego descargarte un par de imágenes para hacer los mensajes un poco más bonitos
cd ~
wget http://blog.internautdesign.com/files/rails_fail.png
wget http://blog.internautdesign.com/files/rails_ok.png
mkdir -p Pictures/Rails_Growl/
mv rails_fail.png Pictures/Rails_Growl/rails_fail.png
mv rails_ok.png Pictures/Rails_Growl/rails_ok.png

luego se edita el fichero .autotest que he modificado un poquillo

  1. require ‘autotest/redgreen’
  2. require ‘autotest/html_report’
  3. require ‘autotest/menu’
  4. module Autotest::Growl
  5.  
  6.   def self.growl msg, options={}
  7.     salida = "growlnotify -n autotest –image \"#{options[:img]}\"  -p #{options[:pri]} -d #{rand(100)} -m \"#{msg}\" \"Tests\" #{options[:sticky]}"
  8.     system salida
  9.   end
  10.  
  11.   Autotest.add_hook :ran_command do |at|
  12.     results = [at.results].flatten.join("\n")
  13.     output = results.slice(/(\d+)\s+assertions?,\s*(\d+)\s+failures?,\s*(\d+)\s+errors?/)
  14.     failures = $~[3].to_i + $~[2].to_i
  15.     options = (failures > 0)? {:img=>"/Users/#{ENV["USER"]}/Pictures/Rails/fail.png", :pri => 0, :sticky => "" } : {:img => "/Users/#{ENV["USER"]}/Pictures/Rails/ok.png", :pri => 0,:sticky => "" }
  16.     output = output.gsub(/assertions/, "aserciones").gsub(/failures/, "fallos").gsub(/errors/, "errores")
  17.     if output
  18.       growl "#{output}", options
  19.     end
  20.   end
  21. end
  22.  

y listo ya podemos correr test en apps ruby y que se nos notifique en growl

Autotest con Growl

Archivado en... Programación, Software, Truquitos, Vida virtual URI





: