Habilitar CORS en Apache
Todas las Apps móviles que se desarrollen con IONIC, por defecto usan WKWebView dejando obsoleto el antiguo UIWebview.
WKWebView fuerza a utilizar CORS y no se puede deshabilitar.
Cross-Origin Resource Sharing (CORS) es un mecanismo que utiliza encabezados HTTP adicionales para indicar a un navegador que permita que una aplicación web que se ejecuta en un origen (dominio) tenga permiso para acceder a los recursos seleccionados de un servidor en un origen diferente. Una aplicación web ejecuta una solicitud HTTP de origen cruzado cuando solicita un recurso que tiene un origen diferente (dominio, protocolo y puerto) que su propio origen.
El estándar de CORS funciona al agregar nuevos encabezados HTTP que permiten a los servidores describir el conjunto de orígenes que tienen permitido leer esa información mediante un navegador web. Además, para los métodos de solicitud HTTP que pueden causar efectos secundarios en los datos del servidor (en particular, para los métodos HTTP que no sean GET, o para el uso de POST con ciertos tipos MIME), la especificación exige que los navegadores «revisen» la solicitud, solicitando métodos compatibles desde el servidor con un método de solicitud de OPTIONS HTTP, y luego, tras la «aprobación» del servidor, se envía la solicitud real con el método de solicitud HTTP real. Los servidores también pueden notificar a los clientes si deben enviarse las «credenciales» (incluidas las cookies y los datos de autenticación HTTP) con las solicitudes.
Por defecto el servidor Apache deniega todas estas peticiones, y contesta únicamente con los modos por defecto que tenga configurados, por lo que es necesario configurar el servidor Apache para que acepte los modos y cabeceras que necesite tu aplicación.
Podríamos pensar en habilitar todo, pero esto no funciona, por lo que tendremos que ir viendo una a una las necesidades.
Las principales características a habilitar en APACHE son:
Access-Control-Allow-Origin (el modo wildcard no se puede usar si en la petición se añaden las credenciales, en ese caso, es necesario ir configurando una a uno los orígenes que queramos habilitar)
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Max-Age
Aquí viene el mayor problema, y es que si desconocemos exactamente las necesidades de la aplicación que accede al servidor Web, tenemos que analizar la primera petición OPTIONS que envía la app para poder habilitarlos en el servidor Apache.
Esto sería relativamente sencillo si las consultas fuesen a un servidor HTTP sin SSL, puesto que podemos hacer un dump de la conexión y revisar esta información, pero en la actualidad la mayoría de las aplicaciones son HTTPS, por lo que si hacemos un DUMP de la conexión, los datos aparecerán encriptados y no podremos investigar la petición OPTIONS de la app.
Para poder hacer esto, vamos el módulo mod_log_forensic de Apache que nos permite registrar las peticiones de los clientes, antes y después de ser procesadas, por lo que en el log que genera este módulo, habrá 2 líneas por cada petición.
Para ello, hay que instalar este módulo y habilitarlo en nuestro servidor de apache, e indicarle una ruta para que almacene el registro de las peticiones de los clientes.
En plesk, tendríamos que ir a:
Herramientas y configuración è Configuración General è Servidor Web Apache y marcamos las casillas de log_forensic y de unique_id è aplicamos y es recomendable también que reiniciemos el servicio de apache
Una vez el módulo de log_forensic, tenemos que ir al dominio sobre el que queremos analizar las peticiones è Configuración de Apache y NGINX y en el apartado de directivas adicionales de apache vamos a añadir la ruta donde queremos habilitar el log, tiene que ser una ruta donde el sitio web o apache tengan permisos de escritura (aprovechamos para guardarlos en la carpeta de logs, por ejemplo:
ForensicLog /var/www/vhosts/sitioweb/logs/cabeceras.log
Aplicamos los cambios, y hacemos una petición con la app al sitio web para que registre las cabeceras.
A continuación, pongo un ejemplo de una línea OPTIONS registrada:
+XJiEEgBx5LGIoSd5JszIwQAAAE0|OPTIONS /apps/service/login/ HTTP/1.1|Host:dat.sincrack.com|Origin:ionic%3a//localhost|Access-Control-Request-Method:POST|Connection:keep-alive|Access-Control-Request-Headers:access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,authorization,content-type,x-auth-token|Accept:*/*|User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57|Accept-Language:es-es|Accept-Encoding:br, gzip, deflate|Content-Length:0
-XJiEEgBx5LGIoSd5JszIwQAAAE0
De esta cabecera podemos averiguar:
- Que el origen es ionic://localhost
- Que el método que solicita es POST
- Que las cabeceras que solicita son: access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,authorization,content-type,x-auth-token
Por lo que en Apache tendríamos que incorporar las siguientes líneas para que funcionase esa petición, luego tendremos que ir viendo el resto de peticiones OPTIONS que se realicen para poder habilitar todas y cada una de las necesidades de la aplicación:
- Header set Access-Control-Allow-Origin » ionic://localhost «
- Header set Access-Control-Allow-Methods «POST»
- Header set Access-Control-Allow-Headers «access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,authorization,x-auth-token»
A continuación, pongo un ejemplo de configuración para un apache (bajo plesk)
- Header set Access-Control-Allow-Origin «*»
- Header set Access-Control-Allow-Methods «GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH»
- Header set Access-Control-Allow-Headers «access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,authorization,x-auth-token»
- Header set Access-Control-Allow-Credentials «true»
- Header set Access-Control-Max-Age «3600»
Si trabajamos con NGINX haciendo de proxy, hay que configurar las cabeceras CORS solamente en NGINX (no configurar en ambos porque se duplica y da error)
Poner las siguientes líneas en el apartado de configuración de NGINX
add_header ‘Access-Control-Allow-Origin’ ‘*’;
add_header ‘Access-Control-Allow-Methods’ ‘GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH’;
add_header ‘Access-Control-Allow-Headers’ ‘access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,authorization,x-auth-token’;
add_header ‘Access-Control-Max-Age’ ‘3600’;
add_header ‘Access-Control-Allow-Credentials’ ‘true’;