En el anterior post expliqué como he implementado WordPress siguiendo, siempre que sea posible, buenas prácticas en AWS y tirando cuando se puede de la capa gratuita para ahorrarnos costes. Voy a hablar ahora de como he configurado el blog a nivel de servidor en la parte de seguridad.
Consideraciones previas
Antes de hablar de seguridad hemos de tener en cuenta que siempre deberemos tener presente que
- Hosting privado > Hosting compartido (por muy bueno que este sea y hay muy buenos)
- Tener actualizado el WordPress es fundamental.
- Tener actualizado los plugins de WordPress es vital.
- Tener actualizado los themes de WordPress es muy importante.
- No utilizar una versión antigua de PHP
- Forzar HTTPS
- Backups, backups,backups
- Cambiar el prefijo por defecto de las tablas de MySQL
- Monitorización y logs configurados correctamente
Otras posibles prácticas podrían ser
- Proteger con un password (via htpasswd) la carpeta wp-admin
- Cambiar la url de acceso a WordPress
- Limitar intentos de sesión via plugin
- Cambiar el wp-admin
Vamos a ver como aplicar algunas medidas de seguridad sobre nuestro WordPress, a veces tirando de configuración del propio WordPress, o configuración del servidor o incluso con algún que otro plugin.
¿Cómo de seguro es mi WordPress?
Bueno, nunca será seguro del todo pero, para tener algo por donde empezar podemos utilizar la herramienta pública de GeekFlare.
Seguridad WordPress
Cambiar la url por defecto de “wp-admin”
La url de wp-admin es mundialmente famoso y por ello, susceptible de ser atacada por fuerza bruta. Con un pequeño plugin podemos ofuscar esta url y devolver un 404 o cualquier otra página. Para ello utilizaremos el plugin WPS Hide Login. Es muy fácil de utilizar y lo bueno es que no necesita de configurar Apache, Nginx o tocar el .htaccess.
Mover Wp-config
Encontré un post interesante vía Kinsta en donde en StackOverFlow un tal Aaron Adams justificaba que mover el archivo wp-config.php era bastante adecuado. Pues oye ,si lo dide Aaron, habrá que hacerle caso.
Quedaría algo así:
# wp-config-fake.php <?php /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); /** Location of your WordPress configuration. */ require_once(ABSPATH . '../wp-config.php');
Y además, prohibiremos que nadie ande merodeando el archivo en sí.
<files wp-config.php> order allow,deny deny from all </files>
Prohibir ejecución PHP en uploads con archivo .htaccess
<Files *.php> deny from all </Files>
Bloquear acceso a wp-includes
A second layer of protection can be added where scripts are generally not intended to be accessed by any user. One way to do that is to block those scripts using mod_rewrite in the .htaccess file. Note: to ensure the code below is not overwritten by WordPress, place it outside the
https://wordpress.org/support/article/hardening-wordpress/# BEGIN WordPress
and# END WordPress
tags in the .htaccess file. WordPress can overwrite anything between these tags.
# Block the include-only files. <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^wp-admin/includes/ - [F,L] RewriteRule !^wp-includes/ - [S=3] RewriteRule ^wp-includes/[^/]+\.php$ - [F,L] RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L] RewriteRule ^wp-includes/theme-compat/ - [F,L] </IfModule>
Deshabilitar edición archivos
The WordPress Dashboard by default allows administrators to edit PHP files, such as plugin and theme files. This is often the first tool an attacker will use if able to login, since it allows code execution. WordPress has a constant to disable editing from Dashboard. Placing this line in wp-config.php is equivalent to removing the ‘edit_themes’, ‘edit_plugins’ and ‘edit_files’ capabilities of all users.
https://wordpress.org/support/article/hardening-wordpress/
define('DISALLOW_FILE_EDIT', TRUE); define('DISALLOW_FILE_MODS',TRUE);
Deshabilitar wp-cron
Este tema daría para un post en sí mismo pero hay muchos posts que hablan ya de esto. Si eres nuevo y no sabes de que va más abajo te dejo un link pero básicamente, wp-cron tiene dos defectos
- Afecta a la escabilidad de WordPress
- Es un posible vector de ataque de fuerza bruta
De momento en este post, te comentaré como deshabilitarlo pero si lo haces, perderás algunas funcionalidades así que, queda bajo tu responsabilidad.
define('DISABLE_WP_CRON', true);
Ofuscar versión de servidor web
ServerSignature Off
ServerTokens Prod
Esto no está relacionado directamente con WordPress pero es buena práctica hacerlo.
Actualizar las claves de seguridad de WordPress
Las claves de seguridad WordPress son un conjunto de variables aleatorias que mejoran el cifrado de la información almacenada en las cookies del usuario. Desde WordPress 2.7 han habido 4 claves diferentes:
https://kinsta.com/es/blog/seguridad-wordpress/AUTH_KEY
,SECURE_AUTH_KEY
,LOGGED_IN_KEY
, yNONCE_KEY
.
Es importante revisarlas sobretodo si hemos estado en hostings compartidos o hace mucho que no las renovamos.
XMLRPC
Viejo conocido por todos. Yo la verdad nunca me acuerdo de esto y siempre acabo recibiendo algún ataque, como hace algunos días que me dejaron la EC2 T2 sin créditos.
¿Qué demonios es el XMLRPC?
El protocolo XMLRPC es un protocolo que utiliza XML para estructurar datos y el protocolo HTTP para la transmisión de esos datos estructurados en XML.
El protocolo XMLRPC fue desarrollado en 1998 por la empresa UserLand Software en colaboración con Microsoft, finalmente Microsoft considero que el protocolo XMLRPC era muy simple y lo convirtió en lo que ahora mismo se llama SOAP.En WordPress, el protocolo XMLRPC actual como interfaz que actúa como API para aplicaciones externas y que nos permite interactuar con una instalación de WordPress utilizando aplicaciones o servicios externos.
Al funcionar como una interfaz externa es casi como una “puerta de entrada” por lo que esta puerta puede ser atacada fácilmente desde el exterior causando un alto consumo de recursos al ejecutarse una y otra vez el proceso de autentificación.
Esta muy bien resumido. “Puerta de entrada”, trasera añadiría yo.
En la mayoría de WordPress con los que he trabajado nunca he visto que nadie lo utilize así que el consejo es claro, evita problemas y bloquea el archivo.
<FilesMatch "^(xmlrpc\.php)">
Order Deny,Allow
Deny from all
</FilesMatch>
¿Si no lo haces? Pues te puede pasar algo como lo que me pasó a mí hace poco. En pocos minutos recibí un ataque de fuerza bruta (buscando passwords, supongo) y no pasó nada pero mi EC2 al ser de tipo T2 se quedó sin créditos.
Not cool bro.
Solo como curiosidad, para saber el origen del ataque podemos utilizar CloudWatch Logs Insights y con un par de queries, obtener la información. Tampoco es que vaya a hacer nada. Es un server en OVH. Pa qué?
Cabeceras de seguridad
Content Security Policy
No voy extenderme tampoco en esto, ya que hay muchos, cientos, de posts donde explican de que va esto de CSP y lo explicarán mejor que yo. Pero en resumidas cuentas, no son más que caberas HTTP. En las que especificamos que recursos se pueden envíar al cliente y desde dónde. Su cometido es reforzar la seguridad de nuestra aplicación para evitar ataques de tipo Cross Site Scripting (XSS).
Content-Security-Policy is the name of a HTTP response header that modern browsers use to enhance the security of the document (or web page). The Content-Security-Policy header allows you to restrict how resources such as JavaScript, CSS, or pretty much anything that the browser loads.
Although it is primarily used as a HTTP response header, you can also apply it via a meta tag.
The term Content Security Policy is often abbreviated as CSP.
https://content-security-policy.com/
Entonces, para añadir esta “capa” de seguridad a nuestro WordPress implementaremos una política o directiva en nuestro servidor, como por ejemplo esta:
Content-Security-Policy:
object-src 'none';
script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
base-uri 'none';
report-uri https://your-report-collector.example.com/
Esta en concreto es una política MUY restrictiva recomendada para sitios en producción.
Algo que me ha parecido muy interesante es que puedes poner el CSP en modo “report-only” y definir un recolector de datos, de manera que enviará todos los posibles fallos para que puedas arreglarlos poco a poco. Evitando dejar a tus usuarios sin servicio, etc. Yo con mi blog he sido un poco agresivo y lo he monitorizado solo unos días. Si se rompe algo, lo volveré a poner en modo report.
Una web que da un servicio totalmente gratis para esto es report-uri.com
Gráfica con fallos detectados en la CSP
Podemos observar el grado de seguridad de nuestra aplicación, utilizando por ejemplo la web de SecurityHeaders.
Resto de cabeceras de seguridad
# Security Headers
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Strict Transport Security (HSTS)
Como digo hay muchas webs que explican esto, me limito a hacer copia y pega, de la página web de Kinsta 🙂 que lo explican perfectamente:
Cualquier intento por parte de los visitantes para usar la versión insegura (HTTP://) de una página en su sitio será automáticamente redirigido a la versión segura (HTTPS://).
Antiguos «favoritos» HTTP y personas usando la versión HTTP de su sitio puedes causar ataques de intermediarios. En estos ataques el atacante altera la comunicación entre las partes y las engaña haciendolas pensar que todavía se comunican entre ellos.
No permite la anulación de mensajes sobre certificado inválido que por su parte realmente protege al visitor.
Secuestros de cookie: esto puede pasar si alguien roba un cookie de sesión a través de una conexión insegura. Cookies pueden contener todo tipo de información valiosa como información de tarjetas de crédito, nombres, direcciones, etc.
https://kinsta.com/es/base-de-conocimiento/hsts-seguridad-transporte-estricta/
X-Frame-Options
Esta cabecera nos sirve para evitar que nuestra página pueda ser accesible desde un frame o iframe. Supuestamente, ayuda a prevenir ataques de tipo clickjacking.
Yo en este caso he sido estricto y he puesto DENY.
X-Content-Type-Options
Con esta otra cabecera de seguridad podemos evitar que un archivo JS o CSS se cargue con un MIME-Type diferente del establecido. Con el valor “nosniff” un archivo CSS no se cargará a menos que su MIME coincida con “text/css”. Es útil porque bloquería archivos enmascarados con un MIME type incorrecto que pueda ejecutar código malicioso en la web.
X-XSS-Protection
Con esta cabecera habilitamos el filtro anti XSS de los navegadores IExplorer y Chrome.
El encabezado de respuesta HTTP
https://developer.mozilla.org/es/docs/Web/HTTP/Headers/X-XSS-ProtectionX-XSS-Protection
es una característica de Internet Explorer, Chrome y Safari que impide la carga de una página cuando detecta ataques del tipo Cross-Site (XSS). Esta protección ya no es necesaria en los navegadores modernos cuando el sitio implementa una fuerteContent-Security-Policy
que deshabilita el uso de Javascript inline ('unsafe-inline'
). Sin embargo da protección a los usuarios de navegadores más antiguos que no soportan CSP
Después de aplicar todas estas cabeceras deberíamos comprobar que puntuación nos dan páginas como SecurityHeaders o Mozilla Observatory
Y por ahora es suficiente, que me está quedando un post largo. En el siguiente, hablaremos de CloudFront y WAF.
Links
- https://content-security-policy.com/
- https://blog.pablofain.com/2019/01/03/usando-csp-para-incrementar-la-seguridad-de-tu-sitio-web/
- https://kinsta.com/es/base-de-conocimiento/hsts-seguridad-transporte-estricta/
- https://www.webempresa.com/blog/cabecera-x-frame-options-mejorar-seguridad-web.html
- https://desarrollowp.com/blog/tutoriales/anadir-cabeceras-http-de-seguridad-en-wordpress/
- https://developer.mozilla.org/es/docs/Web/HTTP/Headers/X-XSS-Protection
- https://raiolanetworks.es/blog/xmlrpc-php-de-wordpress-que-es-y-como-protegerlo/
- https://kinsta.com/es/blog/seguridad-wordpress/
- https://wordpress.org/about/stats/
- https://wordpress.org/support/article/hardening-wordpress/
Actualización
- Añadido “Deshabilitar wp-cron”
- Añadido “Cambiar la url por defecto de “wp-admin”