Політика того самого походження не дає JavaScript з чужого сайту читати відповіді вашого сервера. CORS - спосіб послабити це правило для довірених походжень. Помилки в налаштуванні CORS знімають захист для всіх.
Найнебезпечніша комбінація - віддзеркалення Origin разом з cookie:
# запит з https://attacker.io
Origin: https://attacker.io
# відповідь вразливого сервера
Access-Control-Allow-Origin: https://attacker.io
Access-Control-Allow-Credentials: true
Сервер повторює будь-яке походження з запиту й дозволяє передачу cookie. Сторінка нападника робить fetch('https://app.example/api/me', { credentials: 'include' }) з браузера жертви - і читає її дані, токени, персональну інформацію. Це фактично вимкнена політика того самого походження.
Типові помилки:
- динамічне віддзеркалення
Origin«щоб усе працювало»; - перевірка за підрядком чи «закінченням»:
endsWith('example.com')пропуститьattacker-example.com;str_contains($origin, 'example.com')-example.com.attacker.io. Регулярний вираз без екранування крапки (example.com=example+ будь-який символ +com); - дозвіл походження
null: його надсилають пісочні фрейми (sandbox), локальні файли, деякі редиректи - нападник легко його отримає; - довіра всім піддоменам (
*.example.com) - XSS на будь-якому забутому піддомені стає доступом до основного API; - дозвіл
http://-походжень для HTTPS-сайту - нападник у тій самій мережі може підмінити незахищену сторінку.
Access-Control-Allow-Origin: * з credentials браузер не прийме - тому розробники й починають віддзеркалювати Origin, щоб «обійти» обмеження. Сама * без cookie прийнятна для справді публічних даних.
Правильно:
- явний перелік дозволених походжень, порівняння на точну рівність;
supports_credentialsлише там, де справді потрібні cookie (власний SPA на іншому піддомені);Vary: Origin, якщо відповідь залежить від походження, - інакше CDN закешує відповідь з дозволом для одного походження й віддасть іншим.
У Laravel CORS налаштовується в config/cors.php: allowed_origins - явні значення, allowed_origins_patterns - обережно з регулярними виразами, supports_credentials - лише за потреби.
Пам'ятайте: CORS не захищає сервер від запитів - він лише керує тим, чи може JavaScript прочитати відповідь. Простий POST із чужого сайту все одно дійде до сервера - для цього є CSRF-захист.