En pocas palabras: Asegurar la base de datos de WordPress exige tres movimientos: dar al usuario de MySQL solo los permisos SELECT, INSERT, UPDATE y DELETE, filtrar toda consulta con datos externos mediante $wpdb->prepare() para frenar la inyección SQL, y asumir que el prefijo wp_ es mera ofuscación, no una defensa real.
En la seguridad de WordPress, la base de datos es el botín principal. Asegurarla se resume en tres movimientos: darle al usuario de MySQL solo los permisos indispensables, pasar cada consulta con datos externos por $wpdb->prepare() y asumir que el prefijo wp_ suma poco frente a un ataque bien armado. Lo demás es decoración.
La seguridad en la base de datos de WordPress es el conjunto de prácticas que protegen las tablas MySQL donde vive todo el sitio: contenidos, usuarios, hashes de contraseñas, configuración y estado de cada plugin. Como WordPress impulsa cerca del 43% de la web según W3Techs, un solo ataque de inyección SQL exitoso no compromete un blog aislado: expone usuarios, contraseñas hasheadas y la configuración completa de uno de los sistemas de gestión de contenido más usados del planeta.
En 30 segundos
- Cambiar el prefijo wp_ es ofuscación: complica a los bots que asumen el valor por defecto, pero no frena un ataque dirigido.
- Permisos mínimos de MySQL: SELECT, INSERT, UPDATE y DELETE para operar; CREATE, ALTER, DROP e INDEX para instalar y actualizar.
- $wpdb->prepare() es obligatorio: toda variable que llegue del exterior entra a la consulta vía placeholders %s, %d o %f.
- Los plugins concentran el riesgo: casos documentados por Patchstack como WP Multi Store Locator o Profile Builder Pro muestran dónde entran los atacantes.
- Detección temprana: logs con comillas y UNION SELECT en parámetros GET, usuarios admin fantasma y spam inyectado en posts viejos son señales claras.
¿Qué es la inyección SQL y por qué le importa a tu WordPress?
Una inyección SQL ocurre cuando un atacante mete código SQL dentro de un dato que tu sitio usa para armar una consulta, y la base lo ejecuta como si fuera una instrucción legítima. En WordPress, un caso exitoso termina con lectura completa de wp_users (incluidos los hashes de contraseñas), modificación de wp_options para colgar malware y hasta borrado o secuestro de contenido.
Ponele que tenés un buscador interno y alguien escribe en el campo: ‘ OR ‘1’=’1. Si ese texto entra crudo a la query, la condición siempre da verdadera y la consulta devuelve lo que no debería. Suena antiguo, pero funciona. Complementá con monitorizar cambios sospechosos con Sucuri.
El core de WordPress lleva años endurecido y cada consulta pasa revisión de los equipos de desarrollo, así que el problema se concentra en plugins y temas. Sobre todo en aquellos que arman consultas custom pegando $_GET o $_POST directo en el string SQL. Cuando se habla de seguridad en WordPress, casi todos piensan en contraseñas fuertes y certificados SSL. El botín, en cambio, está en la base.
¿Y qué gana el atacante? Acceso a todo: usuarios, configuración, contenido y la posibilidad de reescribir la URL del sitio para redirigirlo donde quiera.
¿Cambiar el prefijo wp_ mejora la seguridad de WordPress o es un mito?
Cambiar el prefijo ayuda contra los bots que disparan payloads con wp_users y wp_options hardcodeados, pero es la famosa «seguridad por oscuridad»: suma fricción, no defensa. Si el atacante ya ejecuta código en tu servidor, abre wp-config.php, lee el prefijo nuevo y sigue de largo. Ayuda WordPress llega a esa misma conclusión tras analizar el tema a fondo.
La lógica del cambio existe, eso sí. Millones de instalaciones usan wp_ porque es el valor por defecto, así que los scripts maliciosos vienen precocinados para ese caso. Renombrar tablas rompe parte de esa automatización barata. ¿Alguien verificó que detenga ataques dirigidos? Todavía no, y dudo que lo haga.
¿Cómo cambiar el prefijo antes de instalar WordPress?
Antes de instalar, editá $table_prefix en wp-config.php y poné algo como ‘wpx9_’. Listo: todas las tablas nacen con ese prefijo y no hay migración alguna. Es el único escenario donde el cambio sale gratis. Sobre eso hablamos en nuestra guía para proteger las cuentas de administrador con doble factor.
¿Y en un sitio ya instalado?
Hacés backup completo, cambiás el valor de $table_prefix, renombrás cada tabla con RENAME TABLE, actualizás la opción user_roles en la tabla de options, corregís las claves capabilities y user_level en usermeta, y si te olvidás un solo paso, el sitio amanece en pantalla blanca sin explicación aparente.
Nelio Software documenta el proceso completo con sus trampas. Mi consejo después de haber visto sitios rotos por esto: hacelo solo con backup verificado y, si podés, con un plugin especializado que ejecute la migración completa. El beneficio marginal no justifica una pantalla blanca un domingo a la noche.
¿Qué permisos necesita el usuario MySQL de WordPress?
El usuario de base de datos de WordPress necesita ocho privilegios: SELECT, INSERT, UPDATE y DELETE para el día a día, más CREATE, ALTER, DROP e INDEX para instalar componentes y correr actualizaciones. Es la lista que maneja la guía de Melapress sobre privilegios MySQL, y todo privilegio global extra (o usar root directamente) es superficie de ataque regalada.
| Privilegio | Para qué lo usa WordPress | Cuándo es clave |
|---|---|---|
| SELECT | Leer posts, opciones, usuarios y metadata | Siempre |
| INSERT | Crear posts, comentarios y opciones | Siempre |
| UPDATE | Editar contenido y configuración | Siempre |
| DELETE | Eliminar comentarios, posts y transients vencidos | Siempre |
| CREATE | Crear tablas al activar plugins o temas | Instalar componentes |
| ALTER | Modificar estructura de tablas | Actualizar core y plugins |
| DROP | Borrar tablas al desinstalar | Desinstalación limpia |
| INDEX | Crear índices en tablas grandes | Optimización |

Ojo con un detalle que pocos mencionan: si restringís al mínimo absoluto (solo CRUD), la activación de plugins y las actualizaciones van a fallar, porque necesitan crear y alterar tablas. Dos caminos razonables: dejar los ocho privilegios acotados a esa base únicamente, u operar con usuario limitado y elevar temporalmente cuando actualizás. Lo que no se negocia es el alcance: ON mibasededatos.*, nunca *.*
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON mibasededatos.* TO 'wp_usuario'@'localhost';
Desde phpMyAdmin: seleccioná la base, pestaña Privilegios, editá el usuario y tildá solo lo necesario. Si tu hosting te da phpMyAdmin y backups automáticos (donweb.com los incluye en sus planes, por poner un caso local), el ajuste toma cinco minutos.
¿Qué función de WordPress sanitiza las consultas SQL?
$wpdb->prepare() es la función oficial para sanitizar consultas: recibe la plantilla con placeholders y los valores aparte, y devuelve la consulta con los datos escapados. Según la documentación oficial para desarrolladores de WordPress, acepta %s para strings, %d para enteros y %f para flotantes, y desde la versión 6.2 también %i para identificadores como nombres de tabla o columna.
// MAL: concatenación directa, puerta abierta
$usuario = $_GET['user'];
$resultado = $wpdb->get_results(
"SELECT * FROM {$wpdb->users} WHERE user_login = '$usuario'"
);
// BIEN: consulta preparada con placeholder
$usuario = sanitize_text_field( wp_unslash( $_GET['user'] ) );
$resultado = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->users} WHERE user_login = %s",
$usuario
)
);
- Cláusulas IN: generá los placeholders dinámicos con implode() y array_fill(); no metas el array serializado en la query.
- Búsquedas LIKE: pasá el término por $wpdb->esc_like() antes, porque % y _ tienen significado propio en SQL.
- Inserts y updates simples: usá $wpdb->insert(), $wpdb->update() y $wpdb->delete(), que ya aplican prepare() internamente.
¿Y si el plugin que heredaste concatena strings directo? Reescribí esa consulta antes de que la encuentre otro. Más contexto en activar la verificación en dos pasos.
¿Sanitizar y validar es lo mismo?
No, no es lo mismo. Validar es confirmar que el dato cumple lo esperado (un email parece email, un ID es entero positivo); sanitizar es limpiar el dato quitando lo peligroso. Un flujo sano hace las dos cosas: valida primero, sanitiza después, tanto al guardar como al mostrar.
- sanitize_text_field(): limpia texto plano de inputs y textareas, elimina tags y espacios raros.
- sanitize_email(): deja solo caracteres válidos de email; combiná con is_email() para validar.
- absint(): convierte a entero positivo sin sorpresas; ideal para IDs que llegan por GET.
- wp_kses(): permite únicamente el HTML que vos autorices; es la base del filtrado del editor de WordPress.
- esc_sql(): escapa strings para SQL, aunque si la estás usando a mano probablemente quieras prepare() directo.
Aplicá esto en todo punto de entrada: formularios de frontend, handlers de admin-ajax.php, endpoints REST y procesos de importación.
¿Por qué los plugins son la puerta de entrada de la SQLi?
Porque el core se audita a fondo y la larga cola de plugins, no. Casos documentados por Patchstack incluyen inyecciones SQL en WP Multi Store Locator, Profile Builder Pro y el plugin de accesibilidad Ally, varias explotables sin autenticación. Cada plugin con consultas custom es superficie de ataque nueva.
- Concatenación directa: variables de $_GET o $_POST pegadas dentro del string SQL sin prepare().
- Consultas «internas»: páginas de administración custom que asumen que solo admins las alcanzan (spoiler: admin-ajax.php es público).
- Sin chequeos de capacidad: acciones sensibles sin current_user_can() ni nonces.
Para auditar: WPScan enumera plugins contra su base de vulnerabilidades, y los advisories de Patchstack permiten buscar por slug antes de instalar algo. En el rubro de plugins de seguridad, Wordfence aporta firewall a nivel de sitio, Sucuri vende WAF externo y Solid Security (el ex iThemes Security) incluye hardening y hasta el cambio de prefijo automatizado. Ninguno escribe prepare() por vos.
¿Cómo detectar y responder a una inyección SQL en WordPress?
Las señales típicas son parámetros GET con comillas, OR 1=1 o UNION SELECT en los logs, usuarios administrador que nadie creó, spam inyectado en posts viejos y errores de MySQL visibles al público. Cualquiera de esas justifica revisión inmediata. Después, la respuesta sigue un orden claro. Tema relacionado: blindar tu WordPress contra hackers.
- Cortá el acceso: modo mantenimiento o bloqueo temporal mientras investigás.
- Restaurá un backup anterior a la fecha de compromiso; uno posterior reinstala el problema.
- Rotá credenciales: contraseña de la base, claves y salts de wp-config.php, y todas las contraseñas de admin.
- Verificá archivos: con WP-CLI, wp core verify-checksums compara el core contra los originales.
- Actualizá y auditá: core, plugins y temas al día, y revisá la tabla de usuarios y las opciones siteurl y active_plugins.
Para monitoreo continuo, activá el log de errores de MySQL, mantené WP_DEBUG apagado en producción y mirá cada tanto los logs de acceso buscando patrones raros en query strings. Seguridad en WordPress recomienda combinar WAF con auditoría periódica de la base, y coincide con lo que veo en la práctica: el ataque que se detecta tarde es el que duele (y caro).
Errores comunes que dejan la base de datos expuesta
Estos cuatro los veo una y otra vez en auditorías:
- Usar root de MySQL para el sitio: si inyectan SQL, obtienen todas las bases del servidor, no solo la tuya.
- Cambiar el prefijo a medias: renombrar tablas sin actualizar user_roles y usermeta deja el sitio sin usuarios reconocidos.
- Confiar en inputs «privados»: formularios de admin y handlers AJAX son alcanzables desde afuera (sí, en serio); validá igual.
- Dejar display_errors encendido: los mensajes de error filtran nombres de tablas, columnas y fragmentos de consultas.
Preguntas Frecuentes
¿Por qué es importante cambiar el prefijo wp_ de WordPress?
Rompe la automatización de bots que atacan con wp_ hardcodeado, que es el valor por defecto de millones de instalaciones. Es una capa de fricción útil, no una defensa: contra un ataque dirigido no aporta nada, así que nunca debe ser tu única medida.
¿Cómo puedo prevenir ataques de inyección SQL en mi base de datos?
Tres capas: usuario MySQL con privilegios mínimos acotados a tu base, todas las consultas con datos externos pasando por $wpdb->prepare(), y validación más sanitización de cada input. Sumá WAF y auditoría de plugins para cubrir el código que no escribiste vos.
¿Cuáles son los permisos mínimos necesarios para el usuario MySQL de WordPress?
SELECT, INSERT, UPDATE y DELETE para operar, más CREATE, ALTER, DROP e INDEX para instalaciones y actualizaciones. Otorgalos solo sobre la base del sitio (ON mibase.*) y evitá privilegios globales o el usuario root.
¿Qué función de WordPress sanitiza las consultas SQL?
$wpdb->prepare(), definida en la clase wpdb. Recibe la plantilla con placeholders (%s, %d, %f y %i desde WordPress 6.2) y los valores por separado, y devuelve la consulta con los datos escapados de forma segura.
¿Cómo detectar si mi WordPress está siendo víctima de una inyección SQL?
Mirá los logs buscando comillas, OR 1=1 o UNION SELECT en parámetros, revisá si aparecen usuarios admin desconocidos y controlá contenido con spam inyectado. Errores de base de datos mostrándose al público también son señal de alerta.
Conclusión
El orden correcto de la seguridad en WordPress arranca por la base de datos y es claro: primero permisos mínimos en MySQL, después prepare() en cada consulta con datos externos, y recién ahí extras como el cambio de prefijo o un WAF. Nada de esto exige ser experto: una tarde de auditoría alcanza para revisar privilegios, escanear plugins con WPScan y verificar que tus backups se restauran de verdad. Hacelo antes de necesitarlo.
Fuentes
- Documentación oficial de WordPress – referencia de wpdb::prepare()
- Patchstack – guía sobre inyección SQL en WordPress
- Melapress – privilegios seguros de MySQL para WordPress
- Ayuda WordPress – ¿es más seguro cambiar el prefijo de la base de datos?
- Nelio Software – cómo cambiar el prefijo de la base de datos de WordPress
- Seguridad en WordPress – proteger el sitio contra inyección SQL