Cómo validar correctamente datos de $_GET o $_REQUEST usando funciones de WordPress
Estoy trabajando en un plugin que requiere manipulación dinámica del contenido mostrado. Esto depende completamente de la variable actual $_GET
o $_REQUEST
.
Dependiendo de qué valor tenga la variable, llamará a un método específico de una clase para manejar la solicitud del usuario y mostrar el contenido adecuado.
Estoy completamente consciente de la página de Validación de Datos en el Codex de WordPress, sin embargo, no estoy seguro de cuál es el mejor enfoque para mi escenario, o cualquier escenario de sanitización de variables $_GET
o $_REQUEST
.
¿Cómo puedo sanitizar usando funciones de WordPress para variables $_GET
o $_REQUEST
cuando se trata de un string que será comparado para llamar a un método específico de una clase?
¿Podría esto ser explotado o fallar con el siguiente código?:
public function display_admin_page(){
if(is_admin() && isset($_GET['page'])){
global $content;
$page = sanitize_title($_GET['page']);
$method_name = 'page_'.str_replace('-', '_', $page);
if(method_exists('content', $method_name)){
// Mostrar la página solicitada desde la clase content
$thePage = $content->$method_name();
} else{
$thePage = $content->error(404);
}
echo $thePage;
}
}

WordPress no proporciona funciones específicas de validación de datos para las variables SUPERGLOBALES.
Yo uso la función PHP filter_input y luego la escapo como lo haría con cualquier variable no confiable.
$url = filter_input( INPUT_GET, 'some_query_string', FILTER_VALIDATE_URL );
echo '<a href="'. esc_url( $url ). '">Click Me</a>';
El filtro de entrada de PHP acepta:

Para tu ejemplo específico:
Has sanitizado los datos $_GET apropiadamente (aunque yo usaría sanitize_key
en lugar de sanitize_title
-- no hay mucha diferencia, pero sanitize_title
está diseñado para usarse en URLs).
La función method_exists
devolverá verdadero para métodos privados y protegidos, por lo que si un usuario intenta llamar a un método privado o protegido, fallará sin llegar al error 404. (A menos que el método display_admin_page
esté en la misma clase).
Esto nos lleva a la principal vulnerabilidad potencial: que absolutamente cualquier persona puede forzar la ejecución de cualquier método público en tu clase. Si es posible, siempre es mejor crear una lista blanca específica de lo que se puede aceptar. De esa manera podrías validar con algo como:
if ( !in_array( $_GET['page'], array( 'metodo_aceptado', 'otro_metodo_aceptado' ) ) )
$content->error(404);

Claro, me refiero a que es algo que debes analizar. Cada método público en tu clase puede ser forzado a ejecutarse por cualquier persona en cualquier momento. Eso no es automáticamente un exploit, pero es una consideración. ¿Hay algún método en tu clase que elimine de tu base de datos? ¿Hay algún método que muestre las contraseñas de tus usuarios? ¿Agregarás en el futuro otros métodos que puedan ser preocupantes? Etc.

Sanitizar $_GET
es bastante específico al contexto. Depende de qué valor quieras y cómo quieras que sea validado.
No hay una respuesta única que sirva para todos los casos. Es muy específico al contexto. Por ejemplo, podrías escribir una función que elimine todas las etiquetas y barras de la entrada, eso es muy seguro, pero ¿qué pasa si quisieras guardar una etiqueta p? No hay ningún daño ahí. La familia de funciones wp_kses() es un caso interesante, pero no es una gran solución, ya que toma en cuenta el contexto, el nivel de usuario y más. Por ejemplo, como usuario administrador puedes guardar JavaScript en el título y contenido de una entrada, pero con un rol inferior, no puedes.
Si su valor es una cantidad conocida, también puedes verificar si in_array( $array_valid_strings )
y estar completamente seguro de esos valores.
Dicho esto, hay diferentes grados de saneamiento, por lo que es importante mantener tu objetivo final en mente. Consultaría esta lista y encontraría la función o combinación de funciones que se ajuste a tus necesidades. Específicamente son las funciones sanitize_ las que deberían usarse aquí, no las esc_. El saneamiento y el escape continúan siendo confundidos...
En mi caso voy a usar sanitize_text_field() porque sanitiza una cadena de entrada del usuario o de la base de datos.
- Verifica UTF-8 inválido,
- Convierte caracteres individuales < en entidades
- Elimina todas las etiquetas
- Remueve saltos de línea, tabulaciones y espacios extra
- Elimina octetos
Buena suerte :).
P.D. Esta respuesta cita las perspectivas de tres desarrolladores diferentes (Josh, Michal, Kevin).
