Seguridad en WordPress: Códigos imprescindibles
Fernan Díez Colaboraciones 16/06/2017
Hemos hablado largo y tendido sobre WordPress, nuestro gestor de contenidos favorito, pero, ¿qué sucede con las instalaciones que tenemos actualmente activas? ¿Qué podemos hacer para simplificar su mantenimiento? Y, sobre todo, ¿cómo podemos proteger nuestros sitios web dotándolos de mayor seguridad?
No hablaremos en esta ocasión de grandes y reconocidos plugins de seguridad que están a la orden del día, tales como Sucuri Security, iThemes Security Wordfence, y que nos permiten fortalecer la seguridad en varios aspectos. En este caso, ofreceremos fragmentos de código que nos permitirán a través del archivo de funciones de nuestro tema instalado en WordPress.
En muchas ocasiones, menos es más. Conseguiremos resultados preventivos igual de eficaces, pero ahorraremos en complejidad, recursos y problemas de compatibilidad cada vez que nos dispongamos a usarlos.
Seguridad en WordPress: códigos imprescindibles
Comenzaremos con una serie de fragmentos de código que podremos usar en el archivo de funciones, functions.php, de nuestro theme instalado en WordPress.
También podemos usarlos, algo muy recomendable, de manera separada en forma de plugin, lo que nos permitirá que su eficacia perdure en nuestra instalación aunque cambiemos de diseño nuestro sitio web.
Eliminar la información de la versión de WordPress
Con este fragmento de código podremos ocultar la versión de WordPress que estamos utilizando del código fuente de nuestra web, importante medida sobre todo si estuviéramos usando una versión antigua que pudiera tener un problema de seguridad aún no corregido.
// eliminar versión de WordPress de la meta etiqueta y del feed RSS add_filter('the_generator', '__return_false');
Conseguiremos con este código eliminar la versión actual de nuestro WordPress de cualquier archivo CSS o JS en uso en la carga de la página.
// Eliminar el parámetro de versión de cualquier script encolado. function at_remove_wp_ver_css_js( $src ) { if ( strpos( $src, 'ver=' ) ) $src = remove_query_arg( 'ver', $src ); return $src; } add_filter( 'style_loader_src', 'at_remove_wp_ver_css_js', 9999 ); add_filter( 'script_loader_src', 'at_remove_wp_ver_css_js', 9999 );
Ocultar información adicional de la cabecera
Podremos en este caso eliminar información adicional, no necesaria para la carga de la página del header de nuestra web como enlaces a feeds o formatos XML. Debemos tener en cuenta que no las tengamos en uso, no queramos utilizarla. Obviamente, y como cada uno de los elementos que vamos a enumerar, cualquier cambio debe ser realizado con cuidado y comprobado puntualmente.
// Eliminar información adicional de la cabecera function remove_header_info() { remove_action('wp_head', 'feed_links_extra', 3); remove_action('wp_head', 'rsd_link'); remove_action('wp_head', 'wlwmanifest_link'); remove_action('wp_head', 'wp_generator'); remove_action('wp_head', 'start_post_rel_link'); remove_action('wp_head', 'index_rel_link'); remove_action('wp_head', 'parent_post_rel_link', 10, 0); remove_action('wp_head', 'adjacent_posts_rel_link_wp_head',10,0); // for WordPress >= 3.0 } add_action('init', 'remove_header_info');
Deshabilitar las cabeceras X-Pingback y XMLRPC
Las cabeceras las cabeceras X-Pingback ante solicitudes del tipo HTTP y las clases XMLRCP con finalidades similares, no son siempre útliles siendo, además, dos formas de acceso y consulta a nuestra web utilizadas por los atacantes. Conseguiremos con este fragmento evitar mostrar esa información.
// Bloquear las respuestas HTTP a las cabeceras X-PingBack function remove_x_pingback($headers) { unset($headers['X-Pingback']); return $headers; } add_filter('wp_headers', 'remove_x_pingback'); // Deshabilitar la clase XMLRPC add_filter( 'wp_xmlrpc_server_class', '__return_false' ); add_filter('xmlrpc_enabled', '__return_false');
Eliminar mensajes de error relacionados con el acceso
Los mensajes de error que aparecen tras un intento fallido de login a nuestro sitio web con WordPress son de mucha utilidad para los usuarios, pero es también cierto, que pueden ofrecer información sobre la validez de los nombres de usuario, correos electrónicos o cualquier otra credencial utilizada para el acceso.
// Eliminar mensajes de error relacionados con el acceso function login_errors($errors) { global $user_login; if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'lostpassword' || isset($_REQUEST['checkemail'])) { if( preg_match('/There is no user registered with that email address/', $errors) || preg_match('/Invalid username or e-mail/', $errors) || preg_match('/Check your e-mail for the confirmation link/', $errors) ) { $errors = 'If the account information you provided was valid, we have sent you an e-mail. Please check your e-mail for the confirmation link.'; if(!isset($_REQUEST['checkemail'])) { $redirect_to = 'wp-login.php?checkemail=confirm'; wp_safe_redirect( $redirect_to ); exit(); } } } else { if(preg_match('/password you entered for the username/', $errors) || preg_match('/Invalid username/', $errors)) { $errors = 'Your login information was incorrect. <a href="/wp-login.php?action=lostpassword">Lost your password</a>?'; $user_login = $_POST['log']; unset($_POST['log']); if(preg_match('/[@]/', $user_login)) { $errors .= "<br><br>Hint: your email address is not your username."; } } } return $errors; } add_filter('login_errors', array($this, 'login_errors')); add_filter('login_messages', array($this, 'login_errors'));
Eliminar el usuario admin de los comentarios
La información que se muestra públicamente con el funcionamiento habitual de nuestra web, como por ejemplo los comentarios, también puede desvelar datos, como el usuario administrador que estamos utilizando para gestionar la web.
// Eliminar el usuario admin de los comentarios function remove_comment_author_class( $classes ) { foreach( $classes as $key => $class ) { if(strstr($class, "comment-author-")) { unset( $classes[$key] ); } } return $classes; } add_filter( 'comment_class' , 'remove_comment_author_class' );
Evitar mensajes de actualización en el administrador
Podemos también evitar mostrar mensajes de actualización en el panel de administración de WordPress, ocultando información a usuarios identificados tanto de manera correcta como fraudulenta. Especial cuidado, porque deberíamos controlar las actualizaciones por otros medios, evitando estas alertas, podríamos olvidar actualizar y poner en peligro las instalaciones.
// Evitar mensajes de actualización en el administrador function wp_hide_update() { remove_action('admin_notices', 'update_nag', 3); } add_action('admin_menu','wp_hide_update');
Bloquear el acceso al panel de administración
Si un atacante no deseado consigue acceder al panel de administración, aunque no tenga privilegios suficientes, podrá disponer de información importante de nuestra instalación. Evitando el acceso a usuarios que no sean administradores podremos protegernos de mejor modo.
// Bloquear el acceso al panel de administración add_action( 'init', 'blockusers_init' ); function blockusers_init() { if ( is_admin() && ! current_user_can( 'administrator' ) ) { wp_redirect( home_url() ); exit; } }
Deshabilitar el acceso por email
Dificultar el acceso a nuestra instalación reduciendo el número de opciones, nos permite garantizar en mayor medida la seguridad en nuestra instalación de WordPress.
// Deshabilitar el acceso por email remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
WordPress es el gestor de contenidos más utilizado del mundo, y como tal, también el más deseado por los ciberdelincuentes. Un agujero de seguridad, una vulnerabilidad o simplemente, más información de la cuenta, pueden dar más datos de los que se deberían, pudiendo ser aprovechados por todos aquellos que quieran usar nuestro sitio web como subterfugio para conseguir sus objetivos malintencionados.
Como habréis podido comprobar, con unas sencillas líneas de código podremos fortalecer nuestras instalaciones de WordPress en gran modo, evitando algunas de las formas más habituales de acceder a nuestro sitio web y protegiéndonos de muchas amenazas.