Saneamiento y validación de datos con WordPress
Spanish (Español) translation by Marilu (you can also view the original English article)
La seguridad apropiada es crítica para mantener tu sitio o el de tu tema o los usuarios de los plugins a salvo. Parte de ello significa una validación de datos y un saneamiento adecuado. En este artículo vamos a ver por qué esto es importante, qué hay que hacer y qué funciones proporciona WordPress para ayudar.
Como parece haber varias interpretaciones de lo que significan los términos "validación", "fuga" y " saneamiento", primero aclararé lo que quiero decir con ellos en este artículo:
- Validación - Estas son las comprobaciones que se realizan para asegurar que los datos que tienes son los que deberían ser. Por ejemplo, que un correo electrónico se parezca a una dirección de correo electrónico, que una fecha sea una fecha y que un número sea (o se moldee como) un número entero
- Saneamiento / Fuga - Estos son los filtros que se aplican a los datos para hacerlos "seguros" en un contexto específico. Por ejemplo, para mostrar el código HTML en un área de texto sería necesario sustituir todas las etiquetas HTML por sus equivalentes de entidad
¿Por qué es importante el saneamiento?
Cuando los datos se incluyen en algún contexto (digamos en un documento HTML), esos datos podrían ser mal interpretados como un código para ese entorno (por ejemplo, código HTML). Si esos datos contienen un código malicioso, el hecho de utilizarlos sin desinfectarlos significa que ese código se ejecutará. El código ni siquiera tiene que ser necesariamente malicioso para que cause efectos no deseados. El trabajo de saneamiento es asegurarse de que cualquier código en los datos no sea interpretado como código...
Un ejemplo aparentemente inocuo podría ser rellenar previamente un campo de búsqueda con el término actualmente consultado, usando los $_GET['s'] no escapados:
1 |
<form method="get" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>"> |
2 |
<input type="text" class="field" name="s" id="s" value="<?php echo $_GET['s']; ?>"/> |
3 |
<input type="submit" class="submit" name="submit" id="searchsubmit" value="Search" /> |
4 |
</form>
|
Esto abre una vulnerabilidad que podría permitir que se inyecte javascript, por ejemplo, engañando a alguien para que visite http://yoursite.com?s="/>>script>alert('Injected javascript')>/script>. El término de búsqueda "salta" del atributo value, y la siguiente parte de los datos se interpreta como código y se ejecuta. Para evitar esto, WordPress proporciona get_search_query que devuelve la consulta de búsqueda saneada. Aunque se trata de un ejemplo "inofensivo", el script inyectado podría ser mucho más malicioso y, en el mejor de los casos, solo "rompería" la forma si los términos de búsqueda contienen comillas dobles.
La forma en que este código malicioso (o de otro tipo) puede haber llegado a tu sitio no es la preocupación aquí, sino más bien es para evitar que se ejecute. Tampoco hacemos suposiciones sobre la naturaleza de este código no deseado, o su intención, podría haber sido simplemente un error por parte del usuario. Esto me lleva a la regla No.1...
Regla No. 1: No confíes en nadie
Es una expresión común que se usa en relación con el saneamiento de los datos, y es una buena expresión. La idea es que no se debe asumir que los datos introducidos por el usuario son seguros. Tampoco debes asumir que los datos que has recuperado de la base de datos son seguros, aunque los hayas hecho "seguros" antes de insertarlos allí. De hecho, si los datos pueden considerarse "seguros" no tiene sentido sin contexto. A veces los mismos datos pueden ser utilizados en múltiples contextos en la misma página. Los títulos, por ejemplo, pueden contener con seguridad comillas o comillas dobles cuando están dentro de las etiquetas de encabezado, pero causarán problemas si se usan (sin escapar) dentro de un atributo de título de una etiqueta de enlace. Por lo tanto, es bastante inútil hacer que los datos sean "seguros" cuando se agregan a la base de datos, ya que a menudo es imposible hacer que los datos sean seguros para todos los contextos simultáneamente. (Por supuesto que hay que hacerlo seguro para añadirlo a la base de datos, pero llegaremos a eso más tarde).
Incluso si solo tienes la intención de utilizar esos datos en un contexto específico, digamos un formulario, sigue siendo inútil sanear los datos cuando se escriben en la base de datos porque, según la Regla No. 1, no puedes confiar en que sigan siendo seguros cuando los vuelvas a sacar.
Regla No 2: Validar en la entrada, escapar en la salida
Esta es el máximo procedimiento que establece cuándo se deben validar los datos y cuándo se deben sanear. En pocas palabras: validar tus datos (comprobar que son los que deberían ser y que son "válidos") tan pronto como los recibas del usuario. Cuando llegas a usar estos datos, por ejemplo cuando los sacas, necesitas escapar (o sanearlos). La forma que tome este saneamiento depende totalmente del contexto en el que lo uses.
El mejor consejo es realizar esto "tarde": escapar de tus datos inmediatamente antes de usarlos o mostrarlos. De esta forma puedes estar seguro de que tus datos han sido debidamente saneados y no necesitas recordar si los datos han sido previamente comprobados.
Regla No. 3: Confiar en WordPress
Podrías estar pensando "Ok, validar antes de escribir en la base de datos y sanear cuando se use. ¿Pero no tengo que asegurarme de que los datos son seguros para escribir en la base de datos?". En general, sí. Cuando se añaden datos a una base de datos, o simplemente se utiliza una entrada para interactuar con una base de datos, se necesitaría escapar de los datos en caso de que contuviera algún comando SQL. Pero esto me lleva a la Regla No. 3, una que va en contra de la Regla No. 1: Confía en WordPress.
En un artículo anterior, tomé los datos del usuario (enviados desde un formulario de búsqueda a través de AJAX) y los usé directamente con get_posts() para devolver los mensajes que coincidían con esa consulta de búsqueda:
1 |
$posts = get_posts( array( |
2 |
's'=>$_REQUEST['term'] |
3 |
) ); |
Un lector observador se dio cuenta de que no había realizado ningún saneamiento, y tenían razón. Pero no lo necesitaba. Cuando usas funciones de alto nivel como get_posts(), no tienes que preocuparte por sanear los datos, porque las consultas de la base de datos se escapan adecuadamente por los interiores de WordPress. Es un asunto completamente distinto si se utiliza una consulta SQL directa, pero lo veremos en una sección posterior. De manera similar, funciones como the_title(), the_permalink(), the_content() etc. realizan su propio saneamiento (para el contexto apropiado).
Validación de datos
Cuando se reciben datos introducidos por un usuario es importante validarlos. (La API de configuración, cubierta en esta serie, te permite especificar una función de devolución de llamada para hacer exactamente esto). Los datos inválidos se corrigen automáticamente o se aborta el proceso y el usuario vuelve al formulario para intentarlo de nuevo (esperemos que con un mensaje de error apropiado). La preocupación aquí no es la seguridad sino la validez, si lo haces bien, WordPress se encargará de agregar los datos de forma segura a la base de datos. El significado de "válido" depende de ti: podría significar una dirección de correo electrónico válida, un número entero positivo, un texto de longitud limitada o una de una serie de opciones especificadas. Sea cual sea el objetivo de determinar la validez, WordPress ofrece muchas funciones que pueden ayudar.
Números
Cuando se esperan datos numéricos, es posible comprobar si los datos "son algún tipo de número", por ejemplo is_int o is_float. Por lo general, es suficiente con lanzar los datos como numéricos con: intval o floatval.
Si necesitas asegurarte de que el número está relleno con ceros a la izquierda, WordPress proporciona la función zeroise(). La cual toma los siguientes parámetros:
- Número - el número que hay que anotar
- Threshold - el número de dígitos a los que el número será anotado.
Por ejemplo:
1 |
echo zeroise(70,4); // Prints 0070 |
Correos electrónicos
Para comprobar la validez de los correos electrónicos, WordPress tiene la función is_email(). Esta función utiliza simples comprobaciones para validar la dirección. Por ejemplo, comprueba que contiene el símbolo "@", que es más largo que 3 caracteres, el dominio contiene solo alfanuméricos y guiones, y así sucesivamente. Obviamente, no comprueba que la dirección de correo electrónico existe realmente. Asumiendo que la dirección de correo electrónico pasó los controles, se devuelve, de lo contrario se devuelve "false".
1 |
$email = is_email('someone@e^ample.com'); |
2 |
// $email is set to false.
|
3 |
|
4 |
$email = is_email('someone@example.com'); |
5 |
// $email is set to 'someone@example.com'.
|
HTML
A menudo, es posible que quieras permitir solo algunas etiquetas HTML en tus datos, por ejemplo, en los comentarios publicados en tu sitio. WordPress proporciona una familia de funciones del formulario wp_kses_* (KSES Strips Evil Scripts). Estas funciones eliminan (algún subconjunto de) etiquetas HTML, y pueden utilizarse para asegurar que los enlaces en los datos sean de protocolos especificados. Por ejemplo, la función wp_kses() acepta tres argumentos:
-
Content- (cadena) Contenido para filtrar a través de kses -
allowed_html– Un array en la que cada clave es un elemento HTML permitido y el valor es un array de atributos permitidos para ese elemento -
allowed_protocols– Opcional. Protocolo permitido en los enlaces (por ejemplohttp,mailto,feedetc.)
wp_kses() es una función muy flexible, que permite eliminar las etiquetas no deseadas, o simplemente los atributos no deseados de las etiquetas. Por ejemplo, permitir solo las etiquetas <strong> o <a> (pero solo permitir el atributo href)
1 |
$content = "<em>Click</em> <a title='click for wp.tuts+' href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>"; |
2 |
|
3 |
echo wp_kses( $content, array( |
4 |
'strong' => array(), |
5 |
'a' => array('href') |
6 |
) ); |
7 |
|
8 |
// Prints the HTML "Click <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>":
|
9 |
Click <a href="http://wp.tutsplus.com">here</a> to visit <strong> wptuts+ </strong> |
Por supuesto, especificar cada etiqueta y cada atributo permitido puede ser una tarea laboriosa. Por lo tanto, WordPress proporciona otras funciones que permiten utilizar wp_kses con etiquetas y protocolos permitidos preestablecidos, a saber, los que se utilizan para validar los mensajes y los comentarios:
Las funciones anteriores son útiles para garantizar que el HTML recibido del usuario solo contenga elementos de la lista blanca. Una vez hecho esto, también queremos asegurarnos de que cada etiqueta esté equilibrada, es decir, que cada etiqueta de apertura tenga su correspondiente etiqueta de cierre. Para esto podemos usar balanceTags(). Esta función acepta dos argumentos:
- content - Contenido para filtrar y equilibrar las etiquetas de
- force balance - Verdadero o falso, si forzar el equilibrio de las etiquetas
1 |
// Content with missing closing </strong> tag
|
2 |
$content = "<em>Click</em> <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+"; |
3 |
|
4 |
echo balanceTags($content,true), |
5 |
|
6 |
// Prints the HTML "Click <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>"
|
Nombres de archivo
Si quieres crear un archivo en uno de los directorios de tu sitio web, tendrás que asegurarte de que el nombre del archivo sea válido y legal. También querrás asegurarte de que el nombre del archivo es único para ese directorio. Para esto WordPress provee:
-
sanitize_file_name( $filename )- sanea (o valida) el nombre del archivo eliminando los caracteres que son ilegales en los nombres de archivos en ciertos sistemas operativos o que requerirían escapar en la línea de comandos. Sustituye los espacios por guiones y los guiones consecutivos por un solo guión y elimina los puntos, guiones y guiones bajos del principio y el final del nombre del archivo. -
wp_unique_filename( $dir, $filename )- devuelve un nombre de archivo único (para el directorio$dir), saneado (usasanitize_file_name).
Datos de los campos de texto
Al recibir los datos introducidos en un campo de texto, probablemente querrás quitar los espacios en blanco, los tabuladores y los saltos de línea, así como las etiquetas. Para ello WordPress proporciona sanitize_text_field().
Llaves
WordPress también proporciona sanitize_key. Se trata de una función muy genérica (y ocasionalmente útil). Simplemente se asegura de que la variable devuelta contenga solo alfanuméricos en minúsculas, guiones y subrayados.
Saneamiento de datos
Mientras que la validación se ocupa de asegurar que los datos sean válidos, el saneamiento de los datos se ocupa de hacerlos seguros. Si bien algunas de las funciones de validación mencionadas anteriormente podrían ser útiles para garantizar la seguridad de los datos, en general no son suficientes. Incluso los datos "válidos" pueden ser inseguros en ciertos contextos.
Regla No. 4: Hacer que los datos sean seguros es cuestión de contexto
En pocas palabras, no puedes preguntar "¿Cómo hago para que estos datos sean seguros?". En lugar de eso deberías preguntarte: "Cómo hago para que estos datos sean seguros para usarlos en X".
Para ilustrar este punto, supón que tienes un widget con un área de texto en el que pretendes permitir al usuario introducir algo de HTML. Supongamos que entonces entran:
1 |
<textarea name="my-textarea"></textarea> Hello World |
Esto es perfectamente válido, y seguro, HTML, sin embargo, al hacer clic en guardar, nos encontramos con que el texto ha saltado fuera del área de texto. El código HTML no es seguro como valor para el área de texto:


Lo que es seguro de usar en un contexto, no es necesariamente seguro en otro. Siempre que uses o muestres datos debes tener en cuenta qué formas de saneamiento hay que hacer para que el uso de esos datos sea seguro. Por ello, WordPress suele ofrecer varias funciones para el mismo contenido, por ejemplo:
-
the_title- para usar el título en HTML estándar (dentro de las etiquetas de encabezado, por ejemplo) -
the_title_attribute- para usar el título como valor de atributo (normalmente el atributo del título en las etiquetas<a>) -
the_title_rss- para usar el título en los canales RSS
Todos ellos realizan el saneamiento necesario para un contexto particular, y si los utilizas debes asegurarte de usar el correcto. A veces, sin embargo, tendremos que realizar nuestro propio saneamiento, a menudo porque tenemos entradas personalizadas más allá del título estándar del post, permalink, contenido, etc. que WordPress maneja para nosotros.
Escapando del HTML
Al imprimir las variables de la página debemos tener en cuenta cómo las interpretará el navegador. Consideremos el siguiente ejemplo:
1 |
<h1> <?php echo $title; ?> </h1> |
Supongamos que $title = <script>alert('Injected javascript')</script>alert('Injected En lugar de mostrar las etiquetas HTML <script>, se interpretarán como HTML y el javascript adjunto se inyectará en la página.
Esta forma de inyección (como también se demuestra en el ejemplo del formulario de búsqueda) se llama Cross Site scripting y este ejemplo benigno desmiente su gravedad. La secuencia de comandos inyectada puede esencialmente controlar el navegador y "actuar en nombre" del usuario o robar las cookies del usuario. Esto se convierte en un problema aún más grave si el usuario está conectado. Para evitar que las variables impresas dentro de HTML sean interpretadas como HTML, WordPress proporciona la conocida función esc_html. En este ejemplo:
1 |
<h1> <?php echo esc_html($title); ?> </h1> |
Atributos de escape
Consideremos ahora el siguiente ejemplo:
1 |
<?php $value = 'my-value" onfocus="alert(\"Injected javascript\")"'; ?> |
2 |
<input type="text" name="myInput" value="<?php echo $value;?>"/> |
Debido a que $value contiene comillas dobles, si no se escapa puede saltar del atributo de valor e inyectar el guión, por ejemplo, utilizando el atributo onfocus. Para escapar de los caracteres inseguros (como las comillas, y las dobles comillas en este caso), WordPress proporciona la función esc_attr. Al igual que esc_html, reemplaza los caracteres "inseguros" por sus equivalentes de entidad. De hecho, en el momento de redactar el presente documento, estas funciones son idénticas, pero se debe utilizar la que sea apropiada para el contexto.
Para este ejemplo deberíamos tener:
1 |
<?php $value = 'my-value" onfocus="alert(\"Injected javascript\")"'; ?> |
2 |
<input type="text" name="myInput" value="<?php echo esc_attr($value);?>"/> |
Tanto el esc_html como el esc_attr también vienen con variantes __, _e, y _x.
-
esc_html__('Texto a traducir', 'plugin-domain')/esc_attr__- devuelve el texto escapado traducido, -
esc_html_e('Texto a traducir', 'plugin-domain')/esc_attr_e- muestra el texto traducido escapado y finalmente el -
esc_html_x('Texto a traducir', $contexto, 'plugin-domain')/esc_attr_x- traduce el texto de acuerdo al contexto pasado, y luego devuelve la traducción escapada
Nombres de clase HTML
Para los nombres de clase, WordPress proporciona sanitize_html_class - esto escapa a las variables para su uso en los nombres de clase, simplemente restringiendo el valor devuelto a alfanuméricos, guiones y guiones bajos. Nota: No asegura que el nombre de la clase sea válido (referencia: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier).
En el CSS, los identificadores solo pueden contener los caracteres
[a-zA-Z0-9]y los caracteres ISO 10646 U+00A0 y superiores, más el guión (-) y el guión bajo (_); no pueden comenzar con un dígito, dos guiones o un guión seguido de un dígito. Los identificadores también pueden contener caracteres de escape y cualquier carácter ISO 10646 como código numérico.
Escapando de las URLs
Veamos ahora otra práctica común, imprimir variables en el atributo href:
1 |
<a href="<?php echo $url;?>" title="Link Title"> Link Text </a> |
Claramente es vulnerable a la misma forma de ataque como se ilustra en el escape de HTML y atributos. Pero qué pasa si el $url se estableció de la siguiente manera:
1 |
$url = 'javascript:alert(\'Injected javascript\')' |
Al hacer clic en el enlace, la función de alerta se dispararía. Esto no contiene ningún HTML, ni ninguna cita que le permita saltar del atributo href - por lo que esc_attr no es suficiente aquí. Por eso el contexto es importante: esc_attr($url) estaría seguro en el atributo title, pero no para el atributo href, y esto se debe al protocolo javascript, que aunque es perfectamente válido, no debe considerarse seguro en este contexto. En su lugar deberías usar:
-
esc_url- para escapar de los URLs que se imprimirán en la página. -
esc_url_raw- para escapar de URLs para guardarlos en la base de datos o usarlos en la redirección de URLs.
esc_url despoja a varios personajes ofensivos, y reemplaza las comillas y los ampersands con sus equivalentes de entidad. Luego comprueba que el protocolo que se está usando está permitido (javascript, por defecto, no lo está).
Lo que hace esc_url_raw es casi idéntico a esc_url, pero no reemplaza los ampersands y las comillas simples (lo cual no quieres, cuando usas la URL como una URL, en lugar de mostrarla).
En este ejemplo, estamos mostrando la URL, así que usamos esc_url:
1 |
<a href="<?php echo esc_url($url);?>" title="Link Title"> Link Text </a> |
Aunque no es necesario en la mayoría de los casos, ambas funciones aceptan un array opcional para especificar qué protocolos (como http, https, ftp, ftps, mailto, etc.) deseas permitir.
Escapando de JavaScript
A veces querrás imprimir variables de javascript en una página (normalmente en la cabecera):
1 |
<script>
|
2 |
var myVar = '<?php echo $variable; ?>'; |
3 |
</script>
|
De hecho, si estás haciendo esto, es casi seguro que deberías usar wp_localize_script(), que se encarga del saneamiento por ti. (Si a alguien se le ocurre alguna razón por la que podría necesitar usar el método anterior en su lugar, me gustaría oírla).
Sin embargo, para que el ejemplo anterior sea seguro, puedes usar la función esc_js:
1 |
<script>
|
2 |
var myVar = '<?php echo esc_js($variable); ?>'; |
3 |
</script>
|
Escapando del Textarea
Cuando se muestra el contenido en un área de texto, esc_html no es suficiente porque no codifica doblemente las entidades. Por ejemplo:
1 |
<?php $var = '<strong>text</strong> <b>bold</b>' ?> |
2 |
<textarea><?php echo esc_html($var); ?> </textarea> |
$var impreso en el área de texto aparecerá como:
1 |
<strong>text</strong> <b>bold</b> |
En lugar de codificar también el & como & en las etiquetas <b>.
Para ello WordPress proporciona esc_textarea, que es casi idéntica a esc_html, pero hace doble codificación de entidades. Esencialmente es poco más que un envoltorio para htmlspecialchars. En este ejemplo:
1 |
<?php $var = '<strong>text</strong> <b>bold</b>' ?> |
2 |
<textarea><?php echo esc_textarea($var); ?> </textarea> |
Antispambot
Mostrar las direcciones de correo electrónico en tu sitio web los deja propensos a los recolectores de correo electrónico. Un método simple es disfrazar la dirección de correo electrónico. WordPress proporciona antispambot, que codifica partes aleatorias de la dirección de correo electrónico en sus entidades HTML (y equivalentes hexadecimales si $mailto = 1). En cada carga de la página la codificación debería ser diferente y mientras la dirección devuelta se muestra correctamente en el navegador, debería aparecer como un jeroglífico para los robots de spam. La función acepta dos argumentos:
-
e-mail- la dirección para ofuscar -
mailto- 1 o 0 (1 si se utiliza el protocolo mailto en una etiqueta de enlace)
1 |
$email = "joebloggs@example.com"; |
2 |
$email = sanitize_email($email); |
3 |
echo '<a href="mailto:'.antispambot($email,1).'" title="Click to e-mail me" >'.antispambot($email).' </a>'; |
Query Strings (Cadenas de consulta)
Si deseas añadir (o eliminar) variables de una cadena de consulta (esto es muy útil si deseas permitir que los usuarios seleccionen un orden para tus mensajes), la forma más segura y fácil es usar add_query_arg y remove_query_arg. Estas funciones manejan todos los escapes necesarios para los argumentos y sus valores para el uso en la URL.
add_query_arg acepta dos argumentos:
-
query parameters- un array asociativo de parámetros -> valores -
url- la URL para añadir los parámetros y sus valores. Si se omite, se utiliza el URL de la página actual
remove_query_arg también acepta dos argumentos, el primero es un array de parámetros a eliminar, el segundo es como el anterior.
1 |
// If we are at www.example.com/wp-admin/edit.php?post_type=book
|
2 |
$query_params = array ('page' => 'my-bage'); |
3 |
$url = add_query_arg( $query_params ); |
4 |
|
5 |
// Would set $url to be:
|
6 |
// www.example.com/wp-admin/edit.php?post_type=book&page=my-page
|
Validación y Saneamiento
Como se mencionó anteriormente, el saneamiento no tiene mucho sentido sin un contexto, por lo que es bastante inútil sanear los datos al escribir en la base de datos. A menudo, es necesario almacenar los datos en su formato en bruto de todos modos, y en cualquier caso, la Regla No 1 dicta que siempre debemos sanear en la salida.
La validación de los datos, en cambio, debe hacerse tan pronto como se reciban y antes de que se escriban en la base de datos. La idea es que los datos "inválidos" se corrijan automáticamente o se marquen en los datos, y que solo se den a la base de datos los datos válidos.
Dicho esto, es posible que también quieras realizar la validación cuando se muestran los datos. De hecho, a veces, la "validación" también garantiza la seguridad de los datos. Pero la prioridad aquí es la seguridad y se debe evitar una validación excesiva que se ejecutaría en cada carga de la página (las funciones wp_kses_*, por ejemplo, son muy caras de realizar).
Database Escaping
Cuando se utilizan funciones como get_posts o clases como WP_Query y WP_User_Query, WordPress se encarga del saneamiento necesario en la consulta de la base de datos. Sin embargo, cuando se recuperan datos de una tabla personalizada, o se realiza una consulta SQL directa en la base de datos, el saneamiento adecuado depende de ti. WordPress, sin embargo, proporciona una clase útil, la clase $wpdb, que ayuda a escapar de las consultas SQL.
Consideremos este comando básico 'SELECT', donde $age y $firstname son variables que almacenan una edad y un nombre que estamos consultando:
1 |
SELECT * WHERE age='$age' AND firstname = '$firstname' |
No hemos escapado a estas variables, así que potencialmente se podrían inyectar más comandos. Tomando prestado el ejemplo de Xkcd de arriba:
1 |
$age = 14; |
2 |
$firstname = "Robert'; DROP TABLE Students;"; |
3 |
$sql = "SELECT * WHERE age='$age' AND firstname = '$firstname';"; |
4 |
$results = $wpdb->query |
Se ejecutará como la(s) orden(es):
1 |
SELECT * WHERE age='14' AND firstname = 'Robert'; DROP TABLE Students;'; |
Y eliminar nuestra tabla entera Students.
Para evitarlo, podemos usar el método $wpdb->prepare. Esto acepta dos parámetros:
- El comando SQL como una cadena, donde las variables de la cadena son reemplazadas por el placeholder
%sy los números decimales son reemplazados por el placeholder%dy float por%f - Un array de valores para los placeholders anteriores, en el orden en que aparecen en la consulta
En este ejemplo:
1 |
$age = 14; |
2 |
$firstname = "Robert'; DROP TABLE Students;"; |
3 |
$sql = $wpdb->prepare('SELECT * WHERE age=%d AND firstname = %s;',array($age,$firstname)); |
4 |
$results = $wpdb->get_results($sql); |
La consulta SQL escapada ($sql en este ejemplo) puede entonces ser usada con uno de los métodos:
$wpdb->get_row($sql)$wpdb->get_var($sql)$wpdb->get_results($sql)$wpdb->get_col($sql)$wpdb->query($sql)
Inserción y actualización de datos
Para insertar o actualizar datos, WordPress hace la vida aún más fácil al proporcionar los métodos $wpdb->insert() y $wpdb->update().
El método $wpdb->insert() acepta tres argumentos:
- Table name - el nombre de la tabla
- Data - array de datos para insertar como pares column->value
- Formats - array de formatos para los valores correspondientes ('
%s','%d' o '%f')
1 |
$age = 14; |
2 |
$firstname = "Robert'; DROP TABLE Students;"; |
3 |
$wpdb->insert( |
4 |
'Students', |
5 |
array( 'firstname' => $firstname, 'age' => $age ), |
6 |
array( '%s', '%d' ) |
7 |
);
|
El método $wpdb->update() acepta cinco argumentos:
- Table name - el nombre de la tabla
- Data - array de datos para actualizar como pares de column->value
- Where - array de datos para coincidir como pares de column->value
- Data Format - una serie de formatos para los valores de datos correspondientes
- Where Format - conjunto de formatos para los correspondientes valores 'where'.
1 |
// Update Robert'; DROP TABLE Students; to Bobby
|
2 |
|
3 |
$oldname = "Robert'; DROP TABLE Students;"; |
4 |
$newname = "Bobby"; |
5 |
$wpdb->update( |
6 |
'Students', |
7 |
array( 'firstname' => $newname ), |
8 |
array( 'firstname' => $oldname ), |
9 |
array( '%s' ), |
10 |
array( '%s' ) |
11 |
);
|
Tanto el método $wpdb->insert() como el $wpdb->update() realizan toda el saneamiento necesario para escribir en la base de datos.
Como declaraciones
Debido a que el método $wpdb->prepare usa % para distinguir los titulares de los lugares, hay que tener cuidado al usar el comodín % en las declaraciones SQL LIKE. El Codex sugiere escapar de ellos con un segundo %. Alternativamente se puede escapar el término a buscar con like_escape y luego agregar el % de comodín cuando sea apropiado, antes de incluirlo en la consulta usando el método prepare. Por ejemplo:
1 |
$age=14; |
2 |
$firstname = "Robert'; DROP TABLE Students;"; |
3 |
SELECT * WHERE age=$age (firstname LIKE '%$firstname%'); |
Con el que se haría seguro:
1 |
$age=14; |
2 |
$firstname = "Robert'; DROP TABLE Students;"; |
3 |
SELECT * WHERE age=$age AND (firstname LIKE '%$firstname%'); |
4 |
$query = $wpdb->prepare('SELECT * WHERE age=%d AND (firstname LIKE %s);', array($age, '%'.like_escape($firstname).'%') ); |
Resumen
No se trata de una lista exhaustiva de las funciones disponibles para la validación y el saneamiento, pero debería abarcar la gran mayoría de los casos de uso. Muchas de estas (y otras) funciones se pueden encontrar en /wp-includes/formatting.php y te recomiendo encarecidamente que indagues en el código del núcleo y que eches un vistazo a cómo el núcleo de WordPress realiza la validación y saneamiento de los datos.
¿Te ha resultado útil este artículo? ¿Tienes alguna otra sugerencia sobre las mejores prácticas para la validación de datos y el saneamiento en WordPress? Haznos saber en los comentarios de abajo.




