¿Es seguro corregir errores de Access-Control-Allow-Origin (CORS origin) con una directiva de encabezado PHP?

10 oct 2016, 20:21:14
Vistas: 23.9K
Votos: 5

Estoy tratando de mostrar un formulario de Formidable Pro desde un sitio WordPress a otro. Seguí la API del desarrollador y la API REST, pero me encontré con un problema de CORS.

Luego encontré una sugerencia en un hilo del foro que sugería agregar esta línea de código al functions.php del sitio donde está el formulario original:

header("Access-Control-Allow-Origin: *");

Probé este código y funcionó perfectamente.

Mi pregunta es: ¿este código genera riesgos de seguridad u otras vulnerabilidades?

La solución parece demasiado simple para un problema que enfrentan muchas personas.

Agradezco sus comentarios.

2
Comentarios

@markratledge. Gracias por editar la pregunta. Ahora tiene más sentido y ciertamente me ayudó a escribir mejores preguntas.

Atef Wagih Atef Wagih
12 oct 2016 07:29:34

Me pregunto si esta respuesta ayuda: https://wordpress.stackexchange.com/a/226494/51462

Ryan Ryan
13 ago 2017 05:02:57
Todas las respuestas a la pregunta 2
6

Sí, estás abriendo tu sitio para que pueda ser solicitado vía AJAX desde cualquier otro script en toda la web.

Sería mejor si limitas el origen a un dominio remoto específico desde el cual estás consumiendo la API, como este ejemplo:

header("Access-Control-Allow-Origin: http://mozilla.com");

Sin embargo, como indica la documentación de Mozilla, un cliente puede falsificar el origen, pero limitar los sitios a los que un usuario casual puede conectarse es un disuasivo para algunos ataques.

Aún mejor, puedes limitar tus solicitudes a solo los métodos que realmente necesitas permitir, la esencia es este fragmento de código, y funciona para varios dominios, si tienes la variable $_SERVER['HTTP_ORIGIN'] poblada:

add_action('rest_api_init', function() {

     /* desenganchar la función por defecto */
     remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');

     /* luego añadir tu propio filtro */
     add_filter('rest_pre_serve_request', function( $value ) {
          $origin = get_http_origin();
          $my_sites = array( 'http://site1.org/', 'http://site2.net', );
          if ( in_array( $origin, $my_sites ) ) {
              header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
          } else {
              header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
          }
          header( 'Access-Control-Allow-Methods: GET' );

          return $value;
     });
}, 15);

Como puedes ver, este fragmento usa la función get_http_origin proporcionada por WordPress, pero devolverá null o vacío, si la clave HTTP_ORIGIN no está poblada en el array $_SERVER, por lo tanto no está disponible para el script PHP, quizás porque está bloqueado por el proxy de Cloudflare que estás usando. Yo comprobaría rápidamente, con un script con el código <?php phpinfo(); ?>, si tienes esta variable poblada.

Quizás el sitio de origen está poblado en otra cabecera por Cloudflare, y podrías usarlo en una función enganchada al filtro http_origin. Si estás perdido en este punto, edita tu pregunta original publicando los contenidos de la variable _SERVER, excepto tus rutas de sistema de archivos o contraseñas.

Estaré encantado de ayudar.

11 oct 2016 20:17:24
Comentarios

Gracias. La primera solución funcionó para mí. Pero como tengo 4 sitios a los que quiero permitirles acceder al sitio principal, ¿repito la línea 4 veces y cambio la URL del sitio, o se puede combinar en un solo comando? Gracias.

Atef Wagih Atef Wagih
12 oct 2016 11:14:51

Por supuesto que puedes, suelo permitir el acceso a la API solo a unos pocos sitios, he actualizado mi respuesta con la verificación para esto, si funciona, ¿te importaría votar la respuesta?

Jesús Franco Jesús Franco
12 oct 2016 20:25:13

La primera solución funcionó solo para 1 dominio. Si repetí la línea, no funciona. Probé el método en este hilo enlace, pero tampoco funciona. Cuando aplico la solución 2, esto es lo que obtengo: XMLHttpRequest cannot load https://coptic-treasures.com/wp-json/frm/v2/forms/6?return=html. The 'Access-Control-Allow-Origin' header has a value 'https://coptic-treasures.com' that is not equal to the supplied origin. Origin 'https://audio.coptic-treasures.com' is therefore not allowed access.

Atef Wagih Atef Wagih
14 oct 2016 11:39:24

No puedes usar el encabezado Allow Origin más de una vez. He actualizado mi respuesta con más instrucciones para ayudarte a depurar el problema, porque siempre devolver el mismo sitio no debería ocurrir y debería reconocer la lista de dominios que pasas al array. Por favor actualiza tu pregunta con los datos de la variable $_SERVER, devuelta por phpinfo(), excluyendo contraseñas y rutas del sistema de archivos. Estaré encantado de ayudar.

Jesús Franco Jesús Franco
14 oct 2016 21:24:53

Me ha tomado alrededor de 2 días descubrir cómo eliminar el acceso CORS de la API WP-JSON. Gracias por esto. ¡Elimina la llamada a la función rest_send_cors_headers!

dewd dewd
22 nov 2019 19:19:02

Si esto te ayudó, ¿considerarías votar a favor de la respuesta?

Jesús Franco Jesús Franco
22 nov 2019 21:10:52
Mostrar los 1 comentarios restantes
16

Antecedentes - los navegadores están restringiendo el acceso remoto desde scripts solo al sitio desde el cual se cargó. Si no se hiciera este tipo de verificación, mientras visitas un sitio X, sería posible que este enviara datos a tu cuenta de Gmail (si estás logueado) sin siquiera necesitar adivinar tu usuario y contraseña, porque el navegador enviaría las cookies de autenticación adecuadas a Gmail.

El "protocolo" CORS está ahí para ayudarte a relajar esta restricción cuando sea necesario.

Así que la pregunta que debes hacerte es: ¿realmente lo necesito? Por un lado, no veo por qué el 99% de los sitios WordPress lo necesitarían, por otro lado, las cookies de WordPress tienen una vida relativamente corta y el 99% de los sitios WordPress no van a ser objetivo de un ataque aleatorio de este tipo.

Yo diría que, dado que la API REST es mutable y tiene acceso a información privada, no deberías usar la API REST en tu solución si necesitas habilitar CORS. Es mejor que escribas tu propia API de "solo lectura".

11 oct 2016 21:21:33
Comentarios

El OP no está hablando del 99% de los sitios WP que existen, sino de sus propios sitios, y según la pregunta es necesario hacer disponibles recursos desde otro sitio.

Jesús Franco Jesús Franco
13 oct 2016 17:23:13

@JesúsFranco, ¿y cuál es tu punto?

Mark Kaplun Mark Kaplun
13 oct 2016 17:58:44

Que el punto es responder la pregunta, ese es el objetivo de este sitio.

Jesús Franco Jesús Franco
13 oct 2016 19:41:17

@JesúsFranco, creo que mi reputación demuestra que sé cómo responder preguntas y no necesito tus consejos?

Mark Kaplun Mark Kaplun
13 oct 2016 19:50:29

Entonces, ¿tienes una idea específica de cómo el OP puede resolver este problema?

Jesús Franco Jesús Franco
14 oct 2016 21:26:02

@JesúsFranco, el OP preguntó si es seguro. La respuesta es que no lo es. La solución obviamente es no hacer cosas que requieran usar cors

Mark Kaplun Mark Kaplun
15 oct 2016 01:13:43

Mi pregunta se basa en lo que mencionas sobre el riesgo de acceso a información privada. En realidad, uno de los principios fundamentales de la API es que solo el desarrollador puede otorgar acceso a información privada, ya que la API tal como se proporciona originalmente no lo hace.

Jesús Franco Jesús Franco
15 oct 2016 20:16:30

@JesúsFranco Hasta donde yo sé, la API utiliza cookies para autenticación y personas con rol de administrador, por ejemplo, pueden obtener casi cualquier información. Si deshabilitas completamente CORS y estoy usando algún tipo de phishing para llevarte a mi sitio, puedo escribir JS que realizará cualquier operación en tu sitio, porque estás autenticado en él y tu navegador enviará las cookies de autenticación como parte de la solicitud. Ni siquiera necesitaré adivinar tu nombre de usuario... No es suficiente con bloquear el acceso a los endpoints de "escritura", ya que como administrador puedes obtener información clasificada.

Mark Kaplun Mark Kaplun
15 oct 2016 21:50:50

Es posible que actualmente no haya mucho que se pueda obtener con la API, pero su objetivo es poder reemplazar por completo el panel de administración, por lo que tendrá que servir al cliente todos los datos existentes.

Mark Kaplun Mark Kaplun
15 oct 2016 21:52:10

Gracias Mark, conocer el mecanismo que puede ser abusado para convertir el acceso API en algo inseguro, es muy útil para pensar cómo manejar esos riesgos, y luego poder decidir si se puede usar un parche, limitar de otra manera los usos si los métodos utilizables para scripts remotos, o escribir una API completamente nueva.

Jesús Franco Jesús Franco
16 oct 2016 19:43:11

@MarkKaplun Soy nuevo en WP-API así que tenía una pregunta. ¿Permitir CORS solo para métodos 'GET' también expondría el servidor a vulnerabilidades?

Shariq Hasan Khan Shariq Hasan Khan
26 oct 2018 17:41:24

@shariqkhan, probablemente esto sea mejor preguntarlo en SO o en el stack de seguridad, pero en general, la respuesta es sí. CORS debería estar deshabilitado solo para sitios en los que confíes o en subdominios tuyos que no realicen ninguna acción sin credenciales de autorización enviadas en el cuerpo de la solicitud. Mientras la API REST use cookies para autenticación y se ejecute en el mismo dominio que el sitio WP, debes ser muy cuidadoso al deshabilitarlo.

Mark Kaplun Mark Kaplun
27 oct 2018 07:47:11

pero nuevamente, si deshabilitas CORS solo para una URL específica que sabes que no podrá usarse para causar daño, entonces podría estar bien. No es tanto una cuestión de GET vs POST, sino de qué es lo que realmente se está haciendo en ese endpoint

Mark Kaplun Mark Kaplun
27 oct 2018 07:50:42

Gracias @MarkKaplun, he visto muchas de tus respuestas en SO/SE así que sé que sabes de lo que hablas. Probablemente lo preguntaré en SO, aunque siento que la pregunta podría cerrarse por ser "demasiado amplia" o como "duplicada". Me intriga cómo varios sitios web como Github, Twitter (y muchos sitios basados en WordPress también) abren sus APIs deshabilitando restricciones CORS para todos. Tenía la impresión de que si deshabilitas CORS solo para solicitudes GET, es bastante inofensivo porque solo permites que otros obtengan datos y no modifiquen nada.

Shariq Hasan Khan Shariq Hasan Khan
28 oct 2018 08:16:10

La diferencia entre WordPress y otros sitios es que no usan autenticación basada en cookies para la API, y el uso de la API requiere enviar información de usuario y contraseña explícitamente en cada solicitud. La API de WordPress <alerta de rant> estaba mal diseñada en ese aspecto, y probablemente no pudo diseñarse mejor ya que tenía que soportar comunicación insegura sobre HTTP, lo que le impedía usar la técnica de usuario/contraseña ya que cualquiera que escuchara en una (por ejemplo) WiFi habría descubierto los valores.

Mark Kaplun Mark Kaplun
29 oct 2018 04:40:33

el hecho de que tengas las cookies configuradas cuando estás conectado es lo que los atacantes pueden explotar para enviar solicitudes AJAX como si fueran originadas por ti. Con CORS activado, esas solicitudes fallarán para otros dominios, y como eres el único que controla el dominio, estás seguro. Cuantos más sitios para los que desactives CORS, más lugares tendrá un atacante para tomar el control y atacarte induciéndote a visitar ese sitio. La pregunta era sobre desactivar completamente CORS para todos los sitios, lo cual es muy malo, pero si lo desactivas para otro dominio que controlas por completo, aunque no sea algo ideal, no es tan malo.

Mark Kaplun Mark Kaplun
29 oct 2018 04:46:52
Mostrar los 11 comentarios restantes