Plugins (VI) Seguridad en los plugins

Continuando con nuestro viaje por el desarrollo de plugins en WordPress vamos a ver uno de los pasos más importantes en su proceso. La seguridad en los plugins.

Si un plugin tiene fallos de seguridad podría poner en riesgo todo el sistema, por ello WordPress dispone de herramientas de seguridad integradas.

De este modo debemos de saber que todos los datos externos al código del plugin son sospechosos hasta que se demuestre su validez. Los datos siempre han de ser validados antes de mostrarlos en el navegador o añadirlos a la BBDD, para ello vamos a utilizar funciones de escape y limpieza.

Nonce

Los nonces se utilizan en solicitudes para impedir accesos no autorizados mediante la generación de una clave secreta antes de que la solicitud se genere. Tras ello se pasa la clave de la solicitud y se comprueba que sea la misma antes de seguir procesando.

En el siguiente ejemplo vemos como se invoca a la función wp_once_field() dentro de las etiquetas form. Y aunque la función no necesita parámetros obligatorios es recomendable establecer dos.

  • El primero es un $action que debe de ser una cadena exclusiva que describa la acción a realizar.
  • El segundo es un nombre exclusivo para el campo, $name. De forma predeterminada es _wpnonce pero se puede definir cualquier otro nombre personalizado.
<form>
    <?php wp_nonce_field('prowp_settings_form_save', 'prowp_nonce_field');?>
    Introduzca su nombre: <input type="text" name="text" />
    <input type="submit" name="submit" value="guardar opcion"/>
</form>

Cuando invocamos la función wp_nonce_field(), se genera una clave secreta exclusiva que se añade como un campo oculto y que se pasa con los datos del formulario. De esta manera una vez que se envia el formulario debemos de comprobar la clave secreta del nonce por medio de la función check_Admin_referer();

function prowp_update_options(){
    if (isset ($_POST['submit'])){
      //se comprueba el nonce por motivos de seguridad
      check_admin_referer('prowp_settings_form_save', 'prowp_nonce_field');
      //nonce superado, realizar acciones
    }
}

Para comprobar que el nonce es válido tan solo es necesario invocar a la función check_admin_referer() y pasarle la acción y el nombre del nonce exclusivos que hemos definido anteriormente.

Si la clave generada por el nonce no coincide con la creada en el formulario wordpress detiene la ejecución del código y genera un mensaje de error. No es que sea muy bonito pero no nos vamos a andar poniéndole estilos y un front end bonito a un atacante ¿verdad?. De este modo, se impiden las falsificaciones de solicitudes del sitio.

Nonce también se puede utilizar en enlaces que realicen acciones. Para crear un nonce de URL debemos de utilizar la función wp_nonce_url(), la cual puede usarse con varias cadenas de consulta en su URL, como podemos ver a continuación:

<?php $link = 'mi-url.php?action=delete&amp;ID=15'; ?>
<a href="<?php echo wp_nonce_url($link, 'prowp_nonce_url_check');?>">Borrar</a>

De nuevo la función wp_nonce_url() acepta dos parámetros:

  • La url a la que añadir el nonce
  • y su nombre exclusivo.

La cadena wp_nonce se añade al enlace, siendo el valor de la clave secreta generado para el nonce.

De forma muy similar a cuando pasamos los datos por un formulario podemos comprobar que nuestro nonce es correcto:

function prowp_update_options(){
    if (isset ($_GET['action'])){
      //se comprueba el nonce por motivos de seguridad
      check_admin_referer('prowp_nonce_url_check');
      //nonce superado, realizar acciones
    }
}

En esta función se comprueba que nuestra cadena de consulta de acción esté establecida antes de comprobar el valor del nonce. Una vez se valida el nonce, la secuencia de comandos prosigue y si no es valida se detendrá la ejecución para evitar los ataques.

Validación y saneamiento de datos

La validación de datos es algo necesario en nuestros formularios, de ese modo podemos controlar que el usuario no ponga caracteres no permitidos, datos inseguros o inyecciones SQL, de esta forma podremos estar seguros del buen funcionamiento de nuestros plugins.

Aunque todo esto puede hacerse por medio de html5, no esta de más, y de hecho es recomendable que lo hagamos también utilizando las funciones de escape de WordPress antes de mostrar datos por pantalla. Estas funciones nos van a permitir aplicar un estandard de nombres para facilitar las identificación del elemento escapado.

Plantilla de nombres de funciones de escape

wp-esc

Plantilla de nombres de funciones de escape

En el gráfico podemos observar la estructura de la plantilla de funciones de escape que se utiliza para la seguridad en los plugins, en ella podemos diferenciar 3 partes muy claras:

  • esc_: es el prefijo de las funciones de escape
  • attr: es el contexto de escape (attr, html, textarea, js, url y url_raw)
  • _e: es el sufijo de traducción opcional; puede ser __ ó _e

La función esc_html() se utiliza para escapar datos que continen html. Códifica caracteres especiales en sus equivalentes HTML como &, <, >, ” y ‘.

<?php esc_html( $text ); ?>

La función esc_attr() sirve para escapar atributos HTML. Se debe de utilizar siempre que quiera mostras datos dentro de un elemento html.

<input type="text" name="nombre" value="<?php esc_attr( $text ); ?>">

La función esc_textarea() sirve para escapar valores de un textarea de HTML.

<textarea name="descripcion"><?php esc_textarea( $text ); ?></textarea>

La función esc_url() nos sirve para validar URLs, de este modo podemos eliminar los caracteres no permitidos de las mismas.

<a href="<?php esc_attr( $url ); ?>">

Del mismo la función esc_js() escapa cadenas de texto en Javascript:

<script>
    var ejemplo="<?php esc_js( $text) ;>";
</script>

La función esc_sql() da salida a los datos empleados en una consulta MySQL, siendo una forma de abreviar al método $wpdb->escape:

<?php esc_sql($sql)?>

EL prefijo de traducción opcional __ o _e se utiliza para traducir los datos escapados. El sufijo _e reproduce el texto escapado traducido, mientras que __ solo devuelve el valor escapado:

//escapa, traduce y muestra el texto
esc_html_e($text, 'prowp_plugin');

//escapa, traduce, pero NO muestra el texto
$text = esc_html__($text, 'prowp_plugin');

Otras funciones de validación

Existen ostras funciones y formas de validación para mantener la seguridad en los plugins, por ejemplo si los datos que queremos validar deben de ser un número entero, podemos utilizar la función de php intval(), la cual nos devuelve el valor entero de la variable, y si la variable es una cadena nos devuelve 0.

$variable = 123;
$variable = intval($variable);

Tambien podemos utilizar es absint(), la cual comprueba que no se trate de un negativo:

$variable = 123;
$variable = absint($variable);

WordPress cuenta ademas con algunas funciones de saneamiento como:

  • sanitize_text_field(): que elimina todos los caracteres UTF-8 no validos, convierte simbolos < en entidades HTML y elimina etiquetas, saltos de línea y espacios en blanco sobrantes
sanitize_text_field($text);
  • sanitize_email(): elimina los caracteres no permitidos en la dirección mail

Otra función muy completa para procesar y sanear HTML es wp_kses(). Se utiliza para comprobar que los usuarios solo puedan remitir etiquetas y atributos permitidos. Un ejemplo puede ser:

$tags_permitidas = array(
	'strong' =>array(),
	'a' => array(
		'href' => array(),
		'title' => array()
		)
	);
$html = '<a href="#">link</a>.
	Este es: <b>bold</b> y este <strong>strong</strong>';
echo wp_kses($html, $tags_permitidas);

Lo primero que haremos es hacer un array con nuestras tags permitidas y sus atributos, en este casi se permiten las etiquetas a y strong, y en a se permiten los atributos href y title.

Tras ello se crea una variable $html para probar la función.

Finalmente se introduce la variable $html  y el array $tags_permitidas en la función wp_kses().

Lo cual nos da como resultado:

link. Este es: bold y este strong

Podemos ver que las etiquetas <b></b> han sido ignoradas.

Esta función como podemos ver es muy potente y deberíamos de utilizarla siempre que necesitemos que el usuario introduzca algo de código pero controlando que etiquetas permitimos.

Como siempre y para terminar, que esta entrada me ha salido un poco larga, podemos ver más sobre la validación de datos en el codex:

http://codex.wordpress.org/Data_Validation

Nota: Aunque pueda parecer que toda esta información es muy densa, es muy útil para el trabajo que vamos a realizar con nuestros plugins y debe de ser estudiada antes de empezar a crear nuestras aplicaciones personalizadas.