Redes Zombi

Uno de los aspectos más interesantes de la seguridad en redes son las llamadas Redes Zombi, o botnets. Muchas veces nos encontramos con noticias en los medios sobre ataques DDoS o spam masivo, y detrás de esto suelen encontrarse las llamadas redes zombi.

Se trata de conjuntos de ordenadores infectados por software malicioso con una funcionalidad de puerta trasera (backdoor). Esto permite que el atacante tome el control de las máquinas sin disponer de acceso físico a las mismas y sin que el usuario lo sepa, pudiendo utilizarlas para su uso personal (lo que se conoce como drone o bot).

El ciclo de vida de una red zombi comienza con la fase de diseño del software malicioso, que se desarrolla con la intención de provocar una infección masiva. Tras esto llega la fase más importante, la implantación: se infecta a un primer equipo y se deja que el software, de forma vírica, vaya extendiéndose, infectando a más equipos (generalmente a través del correo electrónico, o de malware camuflado como si fuera sofware legítimo). Estas redes se explotan hasta que se detectan y corrigen las vulnerabilidades que lo permiten. Entonces llega una fase de decadencia y finalmente la inactividad de la red.

¿Por qué se crean bots? Tienen muchas formas de explotación, ilegales aunque no siempre ilegítimas. Pueden utilizarse por ejemplo para realizar ataques DDoS (peticiones masivas a un servidor para provocar su caída, a veces con fines económicos aunque en la mayoría de los casos estos ataques se hacen más como medida de protesta contra empresas que realizan prácticas inmorales, como pueden ser Facebook, Amazon, Apple, Microsoft…), aunque su utilización más habitual es para otro tipo de actividades con fines económicos:

  • Spam: Se utilizan las redes para hacer publicidad masiva (buzoneo on-line) por medio del correo electrónico.
  • Fraudes: Puede utilizarse para manipular encuestas, para mejorar estadísticas de jugadores en juegos on-line, para clickar en anuncios y generar beneficios por publicidad…

Otra de sus utilidades es servir como red de proxys para buscar el anonimato en la navegación, dificultando la traza de los datos desde el emisor hasta el receptor. Permiten además disponer de una red de computación distribuida para actividades que requieren mucha potencia, como para intentar romper contraseñas por fuerza bruta.

La forma de explotar estas redes es muy variada. Puede ser realizada de forma personal por el creador de la red, puede alquilar sus servicios a terceros (manteniéndose él como administrador) o puede venderles el software para que ellos creen sus propias redes.

Los consejos para protegerse de este tipo de redes son los básicos consejos de seguridad de siempre:

  • Nunca, jamás, reveléis vuestras contraseñas a servicios dudosos (sí, seguid con esa mierda de «Qué superhéroe eres?» o «Qué tolay con espada de Juego de Tronos serías» en Facebook, que os va dar la risa).
  • El sistema operativo siempre actualizado (quita esa mierda de Vista/XP pirata y ponte un Linux, hombre, que es gratis y la actualización te dará un plus de seguridad)
  • El antivirus, actualizado también, nunca sobra.
  • Ojo con lo que descargas. Si es software libre bájalo desde la web del fabricante. Si estás crackeando algo privativo, intenta que sea de una fuente relativamente fiable.

Y pensad que aunque os molen los zombis, que os zombifiquen el ordenador no es nada bueno. Si queréis participar en un ataque DDoS o prestar algo de vuestro procesador para alguna actividad de red distribuida (legal o no), hacedlo pero sin perder el control sobre vuestro equipo.

Parsear un XML en Ruby

Ando mirando cosillas de Ruby ya que mañana empiezo un curso de SAAS y entre otras cosas he encontrado cómo parsear un xml tirando de Ruby. En Yahoo respuestas me he encontrado dos opciones: Usar REXML o XML-Simple.

En el caso del primero comentan que es lo más típico, ya que REXML es parte de la librería estandard de Ruby. Y como ejemplo de su uso explican cómo utilizarlo para parsear los datos devueltos por el API de Yahoo Web Search.:

require 'net/http'
require 'rexml/document'

# Búsqueda web de la palabra "madonna"
url = 'http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=madonna&results=2'

# obtener los datos xml como una cadena
xml_data = Net::HTTP.get_response(URI.parse(url)).body

# extraer la información del evento
doc = REXML::Document.new(xml_data)
titles = []
links = []
doc.elements.each('ResultSet/Result/Title') do |ele|
   titles << ele.text
end
doc.elements.each('ResultSet/Result/Url') do |ele|
   links << ele.text
end

# imprimir todos los eventos
titles.each_with_index do |title, idx|
   print "#{title} => #{links[idx]}\n"
end

En fin, la cosa no parece muy compleja. Para XMLSimple tampoco hay mucha complicación. Se trata de un port de la librería de Perl XMLSimple que os podéis descargar en este enlace y que para muchos es más intuitivo que REXML. En el ejemplo se haría la misma operación que en el anterior, para que compruebes las diferencias en la sintaxis:

require 'net/http'
require 'rubygems'
require 'xmlsimple'

#buscamos "madonna" y lo cogemos como XML
url = 'http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=madonna&results=2'
xml_data = Net::HTTP.get_response(URI.parse(url)).body

data = XmlSimple.xml_in(xml_data)

#Pateamos los datos y los imprimimos.
data['Result'].each do |item|
   item.sort.each do |k, v|
      if ["Title", "Url"].include? k
         print "#{v[0]}" if k=="Title"
         print " => #{v[0]}\n" if k=="Url"
      end
   end
end

XMLSimple lo que hace es transformar los datos XML a una estructura de datos nativa de Ruby.

En fin, son dos ejemplillos simplones de cómo funcionan ambas librerías para parsear XML. En este enlace tenéis más info sobre REXML y en este sobre XMLSimple para profundizar.

Instalar el módulo para DNIe en un servidor Apache

Estos días estoy realizando el curso de INTECO de desarrollo de aplicaciones del DNIe (os recomiendo que si estáis en paro os paséis por la sección de formación de su web, hay múltiples cursos gratis, que quieras que no ayudan a engordar el CV y a ampliar conocimientos) y, como ejercicio práctico, me he puesto a instalar el módulo para autenticación con DNIe en un servidor Apache.

La idea es instalar el módulo mod_ssl para que apache trabaje con certificados digitales para la autenticación cliente/servidor.

La idea es descargar el módulo, guardarlo en la carpeta /libexec de Apache y ejecutar estos comandos:

cd usr/local/modssl
./configure\
-- with-apache=../apache\
-- with-ssl=../openssl\
-- enable-shared=ssl\

make
make install

Se recompila y reinstala Apache con la opción –enable-module=modssl y ya está. A partir de ahora, para arrancar Apache con ssl se ejecutará el comando

/usr/local/apache/bin/apachectl startssl

Tras esto toca configurar el Apache. Debéis buscar el fichero http.conf, donde estarán todas las directivas de MOD_SSL para su gestión.

La configuración de SSL estará entre una etiqueta ifDefine SSL, dentro de la cual debéis comprobar si está habilitado el protocolo SSL (SSLEngine on). Comprobad por allí que está definido el certificado de servidor y su clave privada (SSLCertificateFile /usr/local/apache/conf/ssl.crt/certificatSERV.crt para el certificado y SSLCertificateKeyFile /usr/local/apache/conf/ssl.key/clausSERV.key ). Luego hay que indicar el directorio donde se guarda la CA (autoridad de certificación) del DNIe, directiva que se utiliza para comprobar si se confía en el emisor del certificado cliente. Busca SSLCACertificateFile acraiz-dnie.cer y SSLCACertificatePath /usr/local/apache/conf/ssl.crt/, el primero es el nombre del certificado y el segundo la dirección donde debe estar guardado. Para cargar el resto de Autoridades de Certificación subordinadas en las cuales se confiará, el procedimiento es el siguiente:

  • Ubicar el certificado en el directorio antes indicado en formato PEM
  • Crear un nombre simbólico de la forma “hash.N” para cada certificado. Se puede hacer con el comando Makefile que proporciona el mismo mod_ssl

Para acabar comprueba que la autenticación del cliente está habilitada (SSLVerifyClient require) y la profundidad de verificación, que para el caso del DNIe se encuentra en las CA subordinadas y la CA Raiz (SSLVerifyDepth 2).

Con todo esto ya tienes el módulo instalado para usar una conexión segura SSL en tu Apache, usando el DNIe para la verificación.

Detectar IE7 o IE6 con Javascript

A día de hoy son muchos todavía los que usan IE6 e IE7. A pesar de que tener un navegador totalmente actualizado y compatible con sistemas operativos con una década de edad es fácil y totalmente gratis, hay gente que se resiste. Si has tenido que hacer páginas web alguna vez sabrás lo engorroso que es tener que contar con estos navegadores. Ya sea para programar una alternativa o para dar un aviso de que ya no das soporte a los mismos (yo es lo que hago últimamente cuando tengo libre albedrío a la hora de diseñar, a modo de concienciación y protesta) es indispensable tener alguna forma de detectar si el navegador es Internet Explorer y qué versión del mismo es.

 var rv = -1;  //inicializamos para prevenir fallos de puntero a nulo
 if (navigator.appName == 'Microsoft Internet Explorer')
 {
      var ua = navigator.userAgent;
      var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
      if (re.exec(ua) != null)
               rv = parseFloat( RegExp.$1 );
      if(rv > -1){
          switch(rv){
              case 7.0:
                "lo que toque hacer";
                 break;
              case 6.0: 
                 "lo que toque si es el 6";
                  break;
              default:
                  "aquí se hace lo que habría que hacer por defecto";
                   break;                  
          }
      }
 }

Y con esto debería ir sin problema la detección.

Tres consejos para el diseño responsivo

Había dejado un poco tiradas las traducciones de Web Designer Wall tras haber hecho dos sobre diseño responsivo y media queries. Ahora voy con el tercer artículo (que curiosamente era el primero que leí) sobre cómo hacer una página con diseño responsivo en tres cómodos pasos.

El primer paso es desactivar la propiedad que hace que en algunos navegadores móviles el tamaño de la página se reduzca al de la pantalla (se reduzca a saco, sin adaptar nada más, dando como resultado muchas veces páginas inusables):

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Bueno, se me olvidaba comentar que como en todas las entradas de esta web hay una demo. Lo siguiente para el diseño es usar adecuadamente la estructura de HTML5, que en el ejemplo sería:

<div id="pagewrap">
  <header></header>
  <content></content>
  <sidebar></sidebar>
  <footer></footer>
</div>

En un principio la altura del header sería de 180 px, la anchura del content de 600 px y la del sidebar de 300.

Y finalmente toca la hora de las media queries para que el diseño se adapte.

Por ejemplo, para una dispositivo con una resolución máxima de 980px pasamos a tamaños relativos:

@media screen and (max-width:980px){
 #pagewrap{
    width:94%;
 }
 content{
    width:65%;
 }
 sidebar{
    width:30%;
 }
}

Para una de menos de 700px modificamos la hoja de estilos para que se posicione la sidebar debajo del contenido:

@media screen and (max-width:700px){
 content{
    width:auto;
    float: none;
 }
 sidebar{
    width:auto;
    float:none;
 }
}

Y para una pantalla de un móvil (máximo de 480 px) reducimos el tamaño de los títulos, dejamos que el ancho de la cabecera (header) se ajuste automáticamente y directamente quitamos la sidebar:

@media screen and (max-width:480px){
 header{
    height:auto;
 }
 h1{
    font-size:24px;
 }
 sidebar{
    display:none;
 }
}

Concluye el artículo remitiendo al de diseño con media queries que yo también traduje en este blog y referencié antes.

Espero que esta pequeña guía tutorial que he traducido, junto a las otras dos traducciones sobre media queries, os hayan servido de ayuda en la edición de vuestros proyectos web. Y si no… jQueryMobile siempre es una ayuda.

Herramientas para revisar la calidad del código Java

Creo que hace un tiempo mi colega El señor Mozano me comentó hace tiempo que hablara de herramientas para el control de calidad del código. Lo dejé colgado, pero he decidido finalmente documentarme, experimentar y lanzar una entrada sobre el tema.

Creo que lo primero es hablar de PDM, una herramienta que controla que se hayan utilizado buenas prácticas de programación: que no haya código duplicado por copypaste, que los algoritmos no se hayan liado y vuelto complejos sin necesidad, que todos los try tengan además del catch su finally… en fin, se trata de una gran herramienta que se integra a la perfección en Eclipse o NetBeans.

Creo que hace tiempo se usaba mucho Checkstyle, pero a mi al menos en las últimas versiones de Eclipse me pareció bastante inútil, porque muchas de sus funcionalidades ya las abarca de por si el IDE. En todo caso, siempre puedes probar, es un revisor de convenciones como la indentación, las convenciones en el nombramiento de variables… etc.

Por su parte Cobertura identifica el porcentaje de código que ha sido accedido en los tests, detectando código inválido o que no ha sido testeado, generando luego un informe en XML.

Me habían recomendado una herramienta llamada FindBugs he de decir que no he trabajado mucho con él en solitario. Busca fallos dentro del código Java haciendo un análisis estático. Es una herramienta desarrollada en Java que requiere de JDK 1.5 como mínimo, aunque es capaz de revisar hasta código en Java 1.0, es libre (licencia LGPL) y fue desarrollado por la universidad de Maryland

Pero todas estas herramientas pueden resumirse en una, la más utilizada: SONAR. Realmente es una recopilación que utiliza algunos de los programas antes citados (al menos seguro FindBugs, Checkstyle y PDM, y algunos más de los que no he hablado) por lo que se trata de una herramienta muy completa. Podéis instalarlo solo o integrado en un Tomcat con MySQL (y puede que haya más opciones, pero me remito a lo aprendido en este tutorial) y existen plugins para otros muchos lenguajes (PHP, Cobol, C, C#, PL/SQL…), aunque nativamente trabaja con Java. Podéis informaros sobre él en la web del proyecto, desde el que lo podéis descargar.

Desde luego que Sonar os ahorrará romperos mucho la cabeza al integrar herramientas ya para todo: buscar duplicados, revisar la arquitectura, el sangrando, la complejidad, los posibles bugs, los comentarios, las convenciones… Pero si queréis probar por separado todas las antes citadas se integran perfectamente en Eclipse.

Encriptación AES en MySQL (y MaríaDB)

El uso de la encriptación AES en MySQL (la más segura de la que dispone el famoso SGBD) es sencillo, y se realiza mediante dos funciones: AES_ENCRYPT y AES_DECRYPT. Permite usar AES_128 o AES_256 dependiendo de la fuente que usemos.

Para insertar o modificar los datos de una columna basta con hacer uso de AES_ENCRYPT, que recibe dos parámetros: el dato a insertar (string) y la clave (string también). A diferencia de SQL-Server, en este caso el dato a encriptar siempre es una cadena. Si quieres conocer de antemano la longitud de la cadena resultado (para ajustar el tamaño del campo en la tabla) lo puedes hacer recurriendo a la fórmula 16 * (trunc(logintud_de_la_cadena / 16) + 1). Si recibe un argumento null el resultado será null también.

Para el caso de AES_DECRYPT los parámetros serán la cadena encriptada a descifrar y la contraseña. Si hay algún error en la encriptación (sea por una modificación maliciosa o por datos de entrada incorrectos) esta función devolverá NULL, aunque es posible que en algún caso pueda dar un valor no nulo erróneo si la cadena encriptada o la contraseña son erróneas.

Una inserción de un registro encriptado se ralizaría de la siguiente forma:

INSERT INTO tb_Ejemplo VALUES(AES_ENCRYPT('valor a encriptar como cadena', 'contraseña'));

En este caso si realizamos una select normal nos devolvería los datos encriptados, para poder verlos tendríamos que hacer

SELECT AES_DECRYPT(COLUMNA_ENCRIPTADA, 'contraseña') FROM tb_Ejemplo;

Finalmente, por seguridad podemos guardar la contraseña en una variable del servidor para no enviarla en cada comunicación con la base de datos, tal que así:

SELECT @pss:='password';
INSERT INTO tb_Ejemplo VALUES (AES_ENCRYPT('texto',@pss));

Sobre cifrado tanto MySQL como MariaDB ofrecen varias opciones aparte de AES, que en este caso es la comentada por ser la más segura y robusta. Pero también existe la posibilidad de usar DES (DES_ENCRYPT y DES_DECRYPT), las funciones DECODE y ENCODE (que no se qué algoritmo usan, la verdad, pero que nos obligan a almacenar los datos en una columna tipo BLOB) y para hashes las funciones MD5, SHA1 y ENCRYPT (que llama a la función crypt() de UNIX, por lo que no puede usarse en Windows). También existe la función PASSWORD, pero es la que usa el sistema de autenticación de MySQL, por lo que se recomienda no usarla en aplicaciones propias.

Encriptar una columna en MS-SQL Server con clave simétrica

Siguiendo con la racha de entradas sobre SQL, vamos a ver cómo encriptar una columna de una tabla SQL-Server usando una clave simétrica.

Bueno, lo primero, tras haber seleccionado la base de datos que queremos usar, es crear una clave maestra si no existe ya, con un password seguro (largo, con mayúsculas, minúsculas, números y símbolos), luego crear un certificado y finalmente una clave simétrica eligiendo el algoritmo a usar (en este caso AES256, robusto y seguro):

IF NOT EXISTS 
    (SELECT * FROM sys.symmetric_keys WHERE symmetric_key_id = 101)
    CREATE MASTER KEY ENCRYPTION BY 
    PASSWORD = 'PoNGo@1#pa55w0rd!fuEr73@para½q@no$me()lo_tAngUen'
GO

CREATE CERTIFICATE NombreDelCertificado
   WITH SUBJECT = 'Certificado Para Ejemplo';
GO

CREATE SYMMETRIC KEY SSN_Clave_Simétrica_01
    WITH ALGORITHM = AES_256
    ENCRYPTION BY CERTIFICATE NombreDelCertificado;
GO

Ok, con esto ya tenemos nuestra clave creada, con su contraseña. Un dato, si sois usuarios de Windows XP o de Windows Server 2000 no podéis usar AES, esos sistemas operativos no lo soportan, tenéis que usar DES (menos robusto y seguro, pero es lo que hay por usar sistemas sin actualizar). Ahora para introducir datos cifrados tienes que hacer lo siguiente:

-- Primero abre la clave simétrica.
OPEN SYMMETRIC KEY SSN_Clave_Simétrica_01
   DECRYPTION BY CERTIFICATE NombreDelCertificado;

--Luego introduce los datos
UPDATE BDEjemplos.Ejemplo
SET ColumnaDatosEncriptados = EncryptByKey(Key_GUID('SSN_Clave_Simétrica_01'), 'Una cadena cualquiera');
GO

En este caso usé un UPDATE pero podría haberlo hecho dentro de un INSERT. En todo caso, la función EncryptByKey() que recibe el identificador de la clave como primer parámetro y el dato a encriptar (String, Real, Float…) como segundo, es la clave de la operación.

Y para acceder a los datos cifados la cosa tampoco se torna muy compleja, es má o menos lo mismo, primero abrir y luego usar una función para desencriptar en la SELECT.En el ejemplo sacaríamos en una columna los datos encriptados y al lado el mismo dato desencriptado.

OPEN SYMMETRIC KEY SSN_Clave_Simétrica_01
   DECRYPTION BY CERTIFICATE NombreDelCertificado;
GO

SELECT ColumnaDatosEncriptados 
    AS 'Dato Encriptado',
    CONVERT(nvarchar, DecryptByKey(ColumnaDatosEncriptados)) 
    AS 'Dato Desencriptado'
    FROM BDEjemplos.Ejemplo;
GO

Existe la posibilidad de hacer esto también con un autenticador para fortalecer la seguridad. Si os interesa podéis mirarlo en la web de ayuda de Microsoft o presionarme para que publique aquí como hacerlo.

La función IFNULL de MySQL

Si el otro día hablaba de la función IF() no es menos interesante la función IFNULL() de MySQL.

En muchos casos te encuentras bases de datos donde en una columna, por falta de restricciones, hay gente que ha usado el nulo en lugar del cero y están todos mezclados (eso me ha pasado a mi, y luego no había forma de cuadrar los balances). O simplemente quieres sacar un listado de producto y deseas que en el nulo ponga un mensaje tipo «no aplicable» (para un descuento) o «sin unidades» (para un registro de almacén). La función IFNULL facilita este trabajo.

Vamos a ver el primer ejemplo citado. Tenemos una columna donde se han usado nulos en valores que realmente deberían llevar cero, y ahora necesitamos exportarlo a Excel y nos va a hacer el lío tenerlos así. Cierto es que una opción sería modificar toda la columna cambiando nulos por ceros, pero supongamos que no es posible (por falta de permisos de edición sobre la tabla, mismamente). En este caso con una línea tal que esta:

SELECT producto, IFNULL(precio, 0) from tbProductos

La función evalúa el primer parámetro y si este es nulo devuelve el valor indicado en el segundo, mientras que si no lo es devuelve el primero. Es decir, en el ejemplo devolvería el precio del producto si no es nulo, y si lo es devolvería cero.

Veamos otro ejemplo, donde probaríamos la función IFNULL con el ejemplo del descuento:

SELECT producto, IFNULL(descuento, 'NO APLICABLE') from tbProductos

La función IFNULL puede devolver valores del tipo INTEGER, REAL o STRING.

Comentar que en MaríaDB también existe, como la mayoría de las funciones de MySQL. Y que en Microsoft SQL-Server existe la función equivalente ISNULL.

La función IF de MySQL

En el SGBD MySQL existe una función bastante útil llamada IF. Obviamente no estoy hablando de una sentencia condicional if para el control de flujo como las que que tenemos en cualquier lenguaje de programación (Visual Basic, C, Java, PHP… y que en MySQL también existe), sino de una función que recibe tres argumentos: una condición a evaluar, un valor a devolver si se cumple y un valor a devolver si no.

Veámoslo ilustrado con el siguiente ejemplo. Tenemos una lista de productos con sus respectivos precios, y nos interesa saber simplemente si el precio es mayor de 60 euros, para separarlos así entre «caros» y «baratos». Aunque podríamos hacerlo con una par de consultas unidas imprimiendo una cadena, ahorraremos código haciéndolo de la siguiente forma:

Select IdProducto, NompreProducto, if(Precio>=60, 'caro','barato')
from tbArtículos

Incluso podemos usar la función IF con funciones de agregado, combinando. En el siguiente ejemplo supongamos que, con la misma tabla de productos, queremos saber si los proveedores nos sirven sólo un producto o si nos sirven más de uno, no nos importa la cantidad, sólo discriminaremos entre uno y más de uno.

Select Proveedor, if(count(*)>1, 'Más de uno','Sólo uno')
from Productos group by Proveedor

La idea es que la función evalúa si el primer parámetro recibido es verdadero y distinto de nulo, y en base a eso devuelve uno de los dos valores, el primero para TRUE y el segundo para FALSE.

Por cierto, la función IF también existe en el fork libre de MySQL MaríaDB, como otras muchas funciones del popular gestor de bases de datos. No está mal recordarlo, por si algún día Oracle se encabrona y nos deja tirados, ya que puede que algún día MaríaDB sea la mejor opción.