CORS vs CSRF: aclarando la confusión

 

CORS vs CSRF: aclarando la confusión

Buena pregunta, porque son dos cosas distintas que suenan parecido y es muy común mezclarlas.

1. CSRF (lo que recuerdas de los formularios)

CSRF = Cross-Site Request Forgery (falsificación de petición en sitios cruzados).

Es un token que Laravel (y otros frameworks) inyecta en los formularios HTML:

html
<form method="POST" action="/posts">
    @csrf   {{-- genera un input hidden con un token --}}
    ...
</form>

¿Para qué sirve? Para asegurar que una petición POST/PUT/DELETE viene de tu propia aplicación y no de un sitio malicioso que quiera actuar en nombre del usuario autenticado. El servidor guarda el token en la sesión y compara el del formulario con el de la sesión. Si no coinciden → 419.

¿Cuándo se usa? Solo en peticiones con estado (sesión/cookies), es decir, formularios web con usuario logueado. No aplica a APIs stateless (APIs que no usan sesiones, como las que usan JWT).

2. CORS (lo que te afecta ahora)

CORS = Cross-Origin Resource Sharing (intercambio de recursos de origen cruzado).

Es un mecanismo del navegador, no del servidor. Bloquea que JavaScript de una página en http://localhost:5173 haga peticiones a http://localhost:8000 si el segundo no lo autoriza explícitamente.

¿Por qué existe? Por seguridad: sin CORS, una web maliciosa podría hacer peticiones silenciosas a tu banco, tu correo, etc. usando las cookies del usuario.

¿Cómo funciona?

  1. El navegador detecta que el origen (localhost:5173) es distinto al destino (localhost:8000).

  2. Envía la petición real, pero primero puede mandar una preflight request con método OPTIONS preguntando: "¿el servidor 8000 permite que 5173 me llame?"

  3. El servidor responde con cabeceras como Access-Control-Allow-Origin.

  4. Si el servidor no las envía → el navegador bloquea la respuesta y ves un error tipo:

    text
    Access to fetch at 'http://localhost:8000/api/hello' from origin 'http://localhost:5173'
    has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...

3. ¿Cuál aplica a tu tutorial?

Tu caso:

  • React corre en http://localhost:5173.

  • Laravel API corre en http://localhost:8000.

  • Ambos son orígenes distintos (distinto puerto → distinto origen, aunque sean el mismo host).

  • Tu API no tiene autenticación todavía (más adelante añadirás JWT).

Conclusión:

Mecanismo¿Aplica a tu tutorial?¿Por qué?
CSRF❌ No (todavía)No usas sesiones ni cookies para autenticar. Cuando añadas JWT, seguirás sin necesitarlo si el token va en el header Authorization.
CORS✅ Sí, es obligatorioEl navegador bloquea la petición de React a Laravel por ser orígenes distintos, aunque no haya autenticación.

Es decir: CORS no tiene nada que ver con autenticación. Es puramente una política del navegador sobre a qué orígenes se les permite leer la respuesta. Aunque tu API sea totalmente pública, el navegador seguirá bloqueando la respuesta si el servidor no manda las cabeceras CORS adecuadas.

4. ¿Es necesario configurarlo en este tutorial?

Sí, para que funcione desde el navegador. Sin CORS, tu fetch() desde React fallará y verás el error en la consola del navegador aunque el endpoint de Laravel funcione perfectamente al abrirlo en el navegador o con curl.

La buena noticia: Laravel 11 ya trae CORS configurado con allowed_origins: ['*'] para rutas api/*. Eso significa que no tienes que tocar nada para este tutorial. Simplemente funciona.

Si usas Laravel 10, ya trae config/cors.php con 'allowed_origins' => ['*'] por defecto. También funciona sin tocar nada.

5. ¿Cuándo sí deberías preocuparte por CORS?

Más adelante, cuando:

  • Quieras restringir qué dominios pueden llamar a tu API (en lugar de *).

  • Añadas JWT y necesites permitir la cabecera Authorization explícitamente (aunque en Laravel 11 ya viene permitido por defecto).

  • Pases a producción y quieras que solo https://midominio.com pueda consumir tu API.

En ese momento, en Laravel 11 modificarías config/cors.php (si no existe, lo publicas con php artisan config:publish cors) y ajustarías:

php
'allowed_origins' => ['https://midominio.com'],
'allowed_methods' => ['*'],
'allowed_headers' => ['*'],

6. Resumen para tu tutorial

  • Puedes dejar CORS como está (funciona out-of-the-box en Laravel 10 y 11).

  • No necesitas configurar nada extra para una API sin autenticación.

  • No confundas CORS con CSRF: CSRF es para formularios con sesión; CORS es una política del navegador sobre orígenes.

  • Cuando implementes JWT, seguirás sin necesitar CSRF (porque no usarás cookies de sesión), pero sí revisarás CORS si quieres restringir orígenes en producción.

Consejo práctico: en tu tutorial, deja una nota corta como esta:

Nota sobre CORS: Laravel incluye CORS habilitado por defecto (allowed_origins: ['*']) para rutas api/*. Esto es suficiente para desarrollo. No confundir con CSRF, que aplica a formularios web con sesión, no a APIs stateless. Cuando pases a producción, restringe allowed_origins a tu dominio real en config/cors.php

Comentarios

Entradas más populares de este blog

12. Hola Mundo en Docker.

2.1-Instalación de Docker (nuevo método oficial), configuración de un proyecto Laravel con Nginx y MySQL en contenedores

11¿Qué es Docker? y ¿Por qué debo saberlo?