Creo este tutorial en vista de los constantes hackeos que sufren nuestros blogs, en mi caso sufría de este mal pero desde que empecé aplicar estos paso mis blogs no han sido hackeados de nuevo pero se ve el intento de estas personas por hacerlo.

A. Cambiar el prefijo de la base de datos de WordPress

Siempre decimos que uno de los básicos a la hora de asegurar tu sitio es no dar información gratis y ¿qué información da WordPress gratis a los posibles hackers?, pues en la versión actual solo el número de versión, incluido en el fichero readme.txt de tu instalación y, acuérdate, el prefijo de la base de datos, que por defecto viene marcado a “wp_” en el fichero ‘wp-config.php‘ creado en la instalación a partir de ‘wp-config-sample.php‘.

Eliminar el fichero readme.txt puedes hacerlo en cualquier momento pero ¿y si no te acordaste de cambiar el prefijo de la base de datos en el momento de la instalación?, ¿puedes hacerlo ahora? …

Pues si, no solo puedes sino que debes hacerlo. Cuando un hacker trate de atacar tu sitio mediante una injección SQL lo primero que va a hacer es comprobar su las tablas de tu base de datos empiezan por ‘wp_’ pues los nombres de las tablas de WordPress son de sobra conocidas (wp_options, wp_posts, wp_comments, etc).

Bueno, no sufras, vamos a cambiar el prefijo ahora mismo, solo necesitas acceso al fichero ‘wp-config.php‘ para editarlo y a phpMyAdmin, algo habitual desde el panel de tu alojamiento, no vamos a tardar más de 10 minutos.

¡Ah!, y como siempre, antes haz copia de la base de datos, eso que no se te olvide por si metes la pata en algún paso.

Nota preliminar: este proceso es para instalaciones ya finalizadas, si aún no has instalado WordPress al hacerlo te pedirá un prefijo para la base de datos, simplemente elige uno poco predecible.

1. Modifica el archivo wp-config.php

Busca la sección que dice esto:

PHP:

/**
 * Prefijo de la base de datos de WordPress.
 *
 * Cambia el prefijo si deseas instalar multiples blogs en una sola base de datos.
 * Emplea solo números, letras y guión bajo.
 */
$table_prefix  = 'wp_';

Aquí es donde vamos al cambiar el prefijo, y lo ideal es usar una cadena que sea difícil de identificar, cuanto más mejor, por ejemplo ‘JUJp4ExX651j’. Asi que sustituimos el predecible ‘_wp’ por esto:

PHP:

/**
 * Prefijo de la base de datos de WordPress.
 *
 * Cambia el prefijo si deseas instalar multiples blogs en una sola base de datos.
 * Emplea solo números, letras y guión bajo.
 */
$table_prefix  = 'JUJp4ExX651j_';

2. Cambiamos los nombres de las tablas de la base de datos

Como en el paso anterior hemos dicho a WordPress que el prefijo de las tablas es distinto al que tienen las existentes no te sorprendas si al acceder a tu sitio te da error, ¡es lo normal!, lo raro sería lo contrario.

Cuando instalas WordPress se añaden nada menos que 11 tablas estándar por defecto en tu base de datos. Luego, si instalas plugins, incluso con algunos temas, la lista va creciendo. Acede a phpMyAdmin y revisa en la lista de la izquierda la lista de tablas de tu base de datos y verás, por lo menos, las 11 originales (aunque seguro que verás más).

Bueno, pues como ya estamos dentro de phpMyAdin elegimos la pestaña SQL y luego el comando RENAME para renombrar rápidamente las tablas de nuestra base de datos, que es lo que toca ahora.

Con los siguientes comandos renombramos las 11 tablas originales de WordPress, recuerda que si tienes más tablas tendrás que añadir una línea similar por cada una adicional ¿entendido?.

Vamos a ello, ejecuta el comando de abajo, solo cambiando el prefijo que yo he puesto aquí al azar por el que tu hayas elegido en el paso anterior.:

Insertar CODE, HTML o PHP:

RENAME table `wp_commentmeta` TO `JUJp4ExX651j_commentmeta`;
RENAME table `wp_comments` TO `JUJp4ExX651j_comments`;
RENAME table `wp_links` TO `JUJp4ExX651j_links`;
RENAME table `wp_options` TO `JUJp4ExX651j_options`;
RENAME table `wp_postmeta` TO `JUJp4ExX651j_postmeta`;
RENAME table `wp_posts` TO `JUJp4ExX651j_posts`;
RENAME table `wp_terms` TO `JUJp4ExX651j_terms`;
RENAME table `wp_term_relationships` TO `JUJp4ExX651j_term_relationships`;
RENAME table `wp_term_taxonomy` TO `JUJp4ExX651j_term_taxonomy`;
RENAME table `wp_usermeta` TO `JUJp4ExX651j_usermeta`;
RENAME table `wp_users` TO `JUJp4ExX651j_users`;

Luego le das a ‘Go’ y tus tablas quedan renombradas de golpe, ya casi hemos terminado.

3. Modifica la tabla wp_options

La tabla ‘wp_options‘ contiene por lo menos un valor que hace referencia a los viejos prefijos de tabla así que hay que cambiarlo. De nuevo ejecutaremos un comando SQL que nos muestre todos los valores de esta tabla que contengan los nombres viejos.

Vamos de nuevo a la pestaña SQL y en la parte superior introducimos lo siguiente, de nuevo cambiando mi cadena aleatoria por la tuya.:

PHP:

SELECT * FROM `JUJp4ExX651j_options` WHERE `option_name` LIKE '%wp_%'

Cuando veas los resultados edita el ‘option_name‘ para cambiar ‘wp‘ a la cadena que elegiste. O sea, que si uno de los ‘option_names‘ es, por ejemplo, ‘wp_user_roles‘, lo cambias a ‘JUJp4ExX651j_user_roles‘, para que haga la referencia a los nuevos nombres de tablas.

4. Modifica la tabla wp_usermeta

Al igual que antes, también en esta tabla hay referencias a “lo antiguo” así que de nuevo hay que ejecutar un comando para terminar el proceso, así que tecleamos lo siguiente para saber lo que nos toca cambiar:

PHP:

SELECT * FROM `JUJp4ExX651j_usermeta` WHERE `meta_key` LIKE '%wp_%'

Ahora lo que toca es cambiar el ‘meta_key‘ de cada resultado para que tenga nuestra cadena “anti-hackers”.

¡Ea ya está!. Ya puedes ir al Escritorio de tu WordPress para comprobar que todo funcione y sabiendo que estás un poco más seguro ante inyecciones SQL.

Nota final: de nuevo, y como en cada ocasión que realices modificaciones en tu WordPress, te recuerdo que hagas copia de seguridad de la base de datos antes de cambiar nada, luego no vengas quejándote.

B. Seguridad en la carpeta “uploads” de WordPress

Una de las más posibles vías de entrada de intrusos en una instalación WordPress es la carpeta “uploads“, situada en la ruta “…/wp-content/uploads“, pues debe tener permisos de escritura para que el mismo WordPress pueda almacenar las imágenes y documentos que subes a través del cargador de medios.

Es por ello que es especialmente importante asegurar lo máximo esta carpeta, para evitar cargas de archivos indeseadas, especialmente si tu WordPress tiene habilitada la publicación de artículos por terceros, incluso invitados y, por supuesto, por hackers indeseables, que los hay.

Lo primero que debes tener en cuenta son los permisos correctos de carpetas en WordPress y, una vez comprobado, podemos añadir un control de seguridad adicional mediante unas líneas de código en un archivo, y al que llamaremos .htaccess (no olvides el punto delante del nombre), y crearemos en la misma carpeta “uploads“.

Sería algo así:
HTML:

# seguridad de subida de archivos en carpeta
<Files ~ ".*\..*">
	Order Allow,Deny
	Deny from all
</Files>
<FilesMatch "\.(jpg|jpeg|jpe|gif|png|bmp|tif|tiff|doc|pdf|rtf|xls|numbers|odt|pages|key|zip|rar)$">
	Order Deny,Allow
	Allow from all
</FilesMatch>

Lo que hacemos es evitar la carga de cualquier archivo salvo los especificados en ‘FilesMatch‘ que, como puedes adivinar, puedes adaptar a tus necesidades (el ejemplo contempla imágenes, pdf, documentos de varios procesadores de texto, hojas de cálculo, presentaciones y archivos comprimidos, bastante amplio). Lo que si que te recomiendo es que no permitas la carga de ficheros con extensiones ejecutables de manera local o remota, como archivos Javascript o similares, por supuesto.

Esto mismo lo puedes hacer en otras carpetas que también requieren la carga de archivos, como “upgrade“, por ejemplo, que la usa WordPress como carpeta temporal para las actualizaciones y demás.

C. Proteger el fichero wp-config.php desde .htaccess

Uno de los archivos más importantes de una instalación de WorPress, si no el más importante, es el archivo de configuración wp-config.php.

Y, en consecuencia, uno de los objetivos de cualquier indeseable que quiera hackear tu WordPress.

Pues bien, buena noticia, proteger este archivo de accesos no deseados es muy sencillo. Solo debes añadir unas líneas de código al fichero .htaccess de tu instalación de WordPress, estas:

HTML:

<Files wp-config.php>
order allow,deny
deny from all
</Files>

Guardas los cambios y ya está. Por supuesto, si no tienes un archivo .htaccess debes crearlo accediendo con tu aplicación cliente FTP.

D. Usa .htaccess como Firewall

El fichero .htaccess es la primera línea de entrada de cualquier sistema web montado sobre Apache, así que también puede convertirse en la primera línea de defensa frente a ataques de hackers, inyecciones de código o intrusiones.

Además, como su construcción es ya veterana está muy documentada y fácil de configurar. Si usas WordPress y has cambiado la estructura de enlaces permanentes, ya tendrás (por lo menos) un fichero .htaccess en la carpeta raíz de tu instalación.

Las cadenas que añade WordPress suelen ser estas:

HTML:

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&lt;/IfModule&gt;
# END WordPress

Y uno de los mejores, y más simples métodos de proteger tu WordPress es añadir reglas que bloqueen automáticamente peticiones basadas en cadenas en la URL.

Por ejemplo, no hay razón alguna (al menos buena) para que una URL empiece con un corchete “[«. Solo hay dos motivos «normales», uno que sea un error de tecleo, y el otro que esté buscando agujeros de seguridad. Así que una primera regla a aplicar para evitar esto sería añadir una regla que provoque una página de error «403 Forbidden» a todo aquel que llegue a tu sitio con la URL comenzando con un corchete.

Añades esto al principio del archivo .htaccess y guardas los cambios:

HTML:

RedirectMatch 403 \[

¿Quieres más?, pues estamos de suerte porque en Perishable Press han creado algo que han llamado el 5G Firewall, que viene a ser una lista de reglas para .htaccess que bloquea una buena cantidad de posibles atacantes que, en su versión actual, nos ofrece esto:

HTML:

# 5G FIREWALL from PerishablePress.com

# 5G:[QUERY STRINGS]
&lt;IfModule mod_rewrite.c&gt;
 RewriteEngine On
 RewriteBase /
 RewriteCond %{QUERY_STRING} (environ|localhost|mosconfig|scanner) [NC,OR]
 RewriteCond %{QUERY_STRING} (menu|mod|path|tag)\=\.?/? [NC,OR]
 RewriteCond %{QUERY_STRING} boot\.ini  [NC,OR]
 RewriteCond %{QUERY_STRING} echo.*kae  [NC,OR]
 RewriteCond %{QUERY_STRING} etc/passwd [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\%27$   [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\\'$    [NC,OR]
 RewriteCond %{QUERY_STRING} \.\./      [NC,OR]
 RewriteCond %{QUERY_STRING} \:         [NC,OR]
 RewriteCond %{QUERY_STRING} \[         [NC,OR]
 RewriteCond %{QUERY_STRING} \]         [NC]
 RewriteRule .* - [F]
&lt;/IfModule&gt;

# 5G:[USER AGENTS]
&lt;IfModule mod_setenvif.c&gt;
 SetEnvIfNoCase User-Agent ^$ keep_out
 SetEnvIfNoCase User-Agent (casper|cmsworldmap|diavol|dotbot)   keep_out
 SetEnvIfNoCase User-Agent (flicky|ia_archiver|jakarta|kmccrew) keep_out
 SetEnvIfNoCase User-Agent (libwww|planetwork|pycurl|skygrid)   keep_out
 &lt;Limit GET POST PUT&gt;
  Order Allow,Deny
  Allow from all
  Deny from env=keep_out
 &lt;/Limit&gt;
&lt;/IfModule&gt;

# 5G:[REQUEST STRINGS]
&lt;IfModule mod_alias.c&gt;
 RedirectMatch 403 (https?|ftp|php)\://
 RedirectMatch 403 /(cgi|https?|ima|ucp)/
 RedirectMatch 403 (\=\\\'|\=\\%27|/\\\'/?|\)\.css\()$
 RedirectMatch 403 (\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\|)
 RedirectMatch 403 \.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$
 RedirectMatch 403 /(contac|fpw|install|pingserver|register)\.php
 RedirectMatch 403 (base64|crossdomain|localhost|wwwroot)
 RedirectMatch 403 (eval\(|\_vti\_|\(null\)|echo.*kae)
 RedirectMatch 403 \.well\-known/host\-meta
 RedirectMatch 403 /function\.array\-rand
 RedirectMatch 403 \)\;\$\(this\)\.html\(
 RedirectMatch 403 proc/self/environ
 RedirectMatch 403 msnbot\.htm\)\.\_
 RedirectMatch 403 /ref\.outcontrol
 RedirectMatch 403 com\_cropimage
 RedirectMatch 403 indonesia\.htm
 RedirectMatch 403 \{\$itemURL\}
 RedirectMatch 403 function\(\)
 RedirectMatch 403 labels\.rdf
&lt;/IfModule&gt;

Estas reglas incluyen la protección contra URLs con corchetes y, como puedes ver, muchísimo más.

E. Restringir acceso a wp-admin

Si quieres evitar que los perfiles de usuario por debajo de un rol determinado tengan acceso al Escritorio de WordPress, a cualquier parte de ‘wp-admin’, o los que no accedan desde una IP concreta, puedes hacerlo de varias maneras.

Como siempre, voy a mostrarte unos cuantos modos, con código, por IP y con plugin, vamos a verlo …

1. Restringir acceso wp-admin con plugin

Hay muchas maneras de proteger el Escritorio pero el plugin que te ofrece más posibilidades es WP Secure, con el puedes limitar el acceso a wp-admin por IP o por tipo de usuario, tu eliges.

2. Restringir acceso wp-admin por IP

Para este método nos valdremos el fichero .htaccess. Primero editamos el existente en la carpeta raíz de tu sitio desde el cliente FTP que uses habitualmente o el navegador de tu proveedor de hosting. Si no existiera lo creas y, en cualquier caso, le añades lo siguiente:

HTML:

<Files wp-login.php>
Order Deny, Allow
Deny from all
Allow from xx.xx.xx.xx

Allow from xx.xx.xx.xx
</Files>

Donde las xx.xx.xx.xx son las IP que SI pueden acceder. Si no sabes tu IP puedes comprobarlo aquí.

Pero no hemos terminado, ahora vas a la carpeta ‘wp-admin’ y creas (si no existiera) otro fichero .htaccess en su interior. En el añades lo siguiente:

Insertar CODE, HTML o PHP:

Order Deny,Allow
Deny from all
Allow from xx.xx.xx.xx
Allow from xx.xx.xx.xx
De nuevo las xx.xx.xx.xx son las IPs autorizadas. Guardas los cambios y ya lo tienes

3. Restringir acceso a wp-admin por código

Para terminar, puedes también conseguir lo mismo añadiendo el siguiente código al fichero functions.php de tu tema activo:

PHP:

<?php
    function restringir_login(){
        global $current_user;
        get_currentuserinfo();

        if ($current_user->user_level <  4) { //si no es admin no entra
            wp_redirect( get_bloginfo('url') );
            exit;
        }

    }
    add_action('admin_init', 'restringir_login', 1);
?>

En este ejemplo todo usuario por debajo del nivel de Administrador (4) no podrá acceder. Así de fácil.