En multitud de programas surge la necesidad de generar un número aleatorio. Aunque quizás parezca algo trivial existen varias malas prácticas que pueden comprometer el funcionamiento de nuestro programa si un usuario mal-intencionado sabe como aprovecharse de ellas.

Por ejemplo, en C/C++ es típico encontrar algo así:

n = 1 + rand() % 10;

para generar un número entre 1 y 10. Esto significa que el valor de n únicamente va a depender del último dígito que devuelva rand(). Lo que no sería problématico si rand() devuelve realmente un número pseudo-aleatorio, pero en implementaciones viejas (y modernas mal hechas) los últimos bits de rand() son no-aleatorios. Por ello es recomendable utilizar bits de mayor orden con algo similar a esto:

n = (int) 1 + 10 * rand() / (RAND_MAX + 1.0);

Si utilizamos una mala impletentación de rand() y un intervalo pequeño, este método es mucho mejor que el anterior ya que utilizamos los bits de mayor orden.

Otro problema importante de la generación de números aleatorios está basado en el Principio_del_palomar. Si tenemos un generador aleatorio para un intervalo de 1 a 10 y suponemos que reparte la probabilidad equitativamente entre los 10 números (mal generador si no) podemos reducir el intervalo entre 1 y 2. Utilizando el típico 1 + rand() % 2 tendríamos algo así:

Valores de rand() para obtener 1:

2,4,6,8,10

Valores de rand() para obtener 2:

1,3,5,7,9

Un total de 5 valores para cada número. Esto está bien pero, ¿qué ocurriría si en vez de 1 y 2 añadimos el número 3? Tendíamos 1 + rand() % 3 y quedaría:

Valores de rand() para obtener 1:

3,6,9

Valores de rand() para obtener  2:

1, 4, 7, 10

Valores de rand() para obtener 3:

2, 5, 8

De esta forma obtenemos una distribución truncada favoreciendo al número 2. Esto ocurre siempre que al hacer la congruencia usemos un número no divisor de RAND_MAX. Con el método anterior evitamos esto ya que al dividir rand() / (RAND_MAX + 1.0) obtenemos un número real en el intervalo [0,1), al multiplicarlo por 3 y convertirlo a entero tendremos 0, 1 o 2 sin haber truncado la probabilidad.

Por último cabe comentar la elección de la semilla para la generación. Los números pseudoaleatorios son totalmente predecibles si conocemos la semilla que origina la secuencia, por ello lo ideal es utilizar algo realmente aleatorio. Lo más común es utilizar la función time(0) aunque hay que tener diversas consideraciones. Lo primero es iniciar la semilla una única vez antes de la primera llamada a rand(). Después, time() tiene una precisión de segundos, es decir, todas las ejecuciones que hagamos en un segundo obtendran la misma secuencia. Esto resulta peligroso en algunas ocasiones, por ejemplo en un juego web que jugaba hace tiempo utilizaban una inicialización de la semilla con este método. Entonces, si por ejemplo al utilizar un item obtenías un beneficio alto, si rapidamente habias actualizado varias ventanas a la vez obtenías en todas el mismo beneficio. Costaba pillarle el truco pero una vez controlado era bastante cantoso el aprovechamiento del fallo  En estos casos se puede utilizar una semilla que dependa dependa de los milisegundos o nanosegundos.

Referencias:

http://www.daniweb.com/forums/thread162830.html#

http://www.eternallyconfuzzled.com/arts/jsw_art_rand.aspx

Algunos dicen (el propio man) que random() es mejor que rand(), para el compilador GCC, pero la página de GNU lo desmiente. Dice que sólo está para portabilidad con BSD y no tiene ninguna ventaja sobre rand().

A raíz de un gracioso email de un amigo advirtiendome de un peligroso ficticio virus que se hace pasar por invitación de Hi 5, acabo leyendo un post sobre el malware en Linux.

¡OH no! ¡Existen virus para linux, y yo sin anti-virus! Qué pesados, qué cansinos! En mi opinión toda la industria de los anti-virus es un cuento para ganar dinero. No los uso ni en Windows, ni muchísimo menos en Linux, los detesto. Sé que es una postura radical, por lo que voy a defenderla un poco desde mi punto de vista.

Para empezar distingamos entre virus y malware, aunque sólo sea para aclarar el sentido del post (no es una definición exacta sino más bien mi forma de entederlo). Un virus, o lo que yo entiendo por virus, necesariamente debe explotar algún fallo en el código fuente de otro programa (por ejemplo el Blaster y el RPC). Esto implica que el virus no tiene porque ser un ejecutable, y tampoco tiene porque ser, la «infección», necesariamente culpa de una negligencia del usuario. Por otro lado, consideremos el malware todo software perjudicial para nuestros ordenadores que no aprovecha un fallo de otro programa, por tanto es necesario que sea un ejecutable y que el usuario lo ejecute (negligencia del usuario).

¿Qué sitio queda para los anti-virus tras esta distinción? En el caso de los virus, es casi imposible que el anti-virus  lo detecte si aún no se conoce el virus. Y lo que es peor, ese trabajo invertido en el anti-virus será totalmente inútil una vez el fallo que aprovechaba el virus sea corregido (por no hablar de esos pobres ciclos de reloj sacrificados para ejecutar el anti-virus). En el caso del malware, el anti-virus vendría ser como un padre diciendole a su hijo, «eso no, caca». ¿No debe ser el usuario responsable de lo que instala y ejecuta?,¿no existen grandes medios hoy en día para conseguir software fiable y seguro? (ejem: repositorios), ¿no debe saber el usuario que no debe ejecutar un archivo de un correo si no se fía de la procedencia? ¿Por qué no invertir el tiempo y los recursos mejorando el software e informando a los usuarios en vez de hacerlo con anti-virus y creando alarma y miedo? Por dinero, claro está…

Para acabar, no sólo discuto la supuesta utilidad de los anti-virus en general, también está su falta de transparencia y sus falsos positivos. ¿Cuantas veces has mandado un mp3 por messenger y este ha sido borrado? ¿De verdad crees que tienes los nosecuantos mil virus que tu anti-virus ha detectado?

Nota: Dicen que los programadores de malware (y/o virus, supongo) se empiezan a centrar en Linux porque éste cada vez tiene más usuarios. Y digo yo: ¿no serán las empresas de anti-virus las que ven en Linux un mercado creciente? Todos los anti-virus excepto uno citados en la wikipedia son comerciales o de código privativo  y curiosamente el único libre parece más orientado a servidores que a sistemas desktop.

PD: Bueno os dejo que tengo que actualizar el Norton 😀