Модуль 19

CORS і безпека API

Ось готовий урок, створений спеціально для тебе у стилі David Malan. Вмикаймо уяву, відкриваймо термінал і — поїхали! 🚀


🎓 Урок: CORS і безпека API

(Або: "Чому браузер блокує мої запити і як з цим жити")


1. 🔥 Вступ: Проблема та мотивація

Уявіть ситуацію. Ніч, кава, тиша. Ви пишете свій геніальний проєкт. У вас є Frontend на React, який крутиться на localhost:3000. І є потужний Backend (Node.js, Python чи Go), який працює на localhost:8000.

Ви робите простий запит fetch('http://localhost:8000/api/data'), щоб отримати дані для користувача. Ви очікуєте побачити JSON. Але натомість відкриваєте консоль браузера і бачите ЧЕРВОНЕ МОРЕ помилок:

Access to fetch at '...' from origin '...' has been blocked by CORS policy.

Зізнавайтесь, хотілося в цей момент просто вдарити по клавіатурі?

Чому? Чому браузер заважає мені працювати? Я ж автор і того, і іншого коду!

А тепер питання: Якби браузери дозволяли будь-якому сайту робити запити до будь-якого іншого сайту без дозволу, що б сталося з вашим банківським рахунком, поки ви читаєте новини на підозрілому сайті?

Аналогія: Уявіть, що ваш браузер — це консьєрж у багатоквартирному будинку (ваш комп'ютер). Сайт А (зломисник) намагається відправити кур'єра (запит) у квартиру Сайту Б (ваш банк), щоб забрати звідти гроші. Без правил безпеки кур'єр зайде і винесе все. CORS (Cross-Origin Resource Sharing) — це інструкція для консьєржа: "Цьому кур'єру можна заходити тільки якщо господар квартири Б дав йому перепустку".

Без розуміння CORS ви не зможете з'єднати фронтенд з бекендом. Крапка.


2. 🧠 Теоретична база (без сухої академічності)

Давайте розберемо це "під капотом". Але без нудних специфікацій.

Що таке Origin?

Це "адреса прописки" вашого сайту. Вона складається з трьох частин: 1. Протокол (http:// або https://) 2. Домен (google.com або localhost) 3. Порт (:3000, :80, :443)

Якщо хоч одна літера відрізняється — це інший Origin. * http://localhost:3000 і http://localhost:8000РІЗНІ (різні порти). * http://site.com і https://site.comРІЗНІ (різні протоколи).

Same-Origin Policy (SOP) — Правило "Тільки свої"

За замовчуванням браузер каже: "Скрипт з одного джерела може читати дані ТІЛЬКИ з того ж самого джерела". Це SOP. Це найважливіший механізм безпеки в інтернеті.

То що ж таке CORS?

Це спосіб послабити SOP. Це механізм, який дозволяє серверу сказати браузеру: "Гей, все ок! Я знаю хлопців з localhost:3000, дозволь їм взяти ці дані".

Як це працює? (Діалог браузера і сервера)

  1. Браузер: "Привіт, Сервере! Скрипт із сайту А хоче отримати дані."
  2. Сервер: Відправляє дані + спеціальний Header (заголовок): Access-Control-Allow-Origin: http://site-A.com.
  3. Браузер: Дивиться на заголовок. Якщо сайт А там є — віддає дані скрипту. Якщо немає (або заголовок відсутній) — показує помилку CORS.

❗️ Запам'ятайте головне: CORS — це захист на стороні браузера. Якщо ви зробите той самий запит через Postman або cURL (у терміналі), він пройде успішно! Сервер віддасть дані. Саме браузер вирішує, чи показувати їх вам, чи приховати заради безпеки.


3. 🧪 Приклади (від простого до реального)

Приклад 1: "Катастрофа"

Код клієнта (JS):

fetch('http://api.myserver.com/users');

Відповідь сервера: (Звичайний JSON, без заголовків CORS)

Що ви очікуєте? Дані користувачів. Реальність: Помилка в консолі. Браузер заблокував відповідь, бо сервер "промовчав" про дозволи.


Приклад 2: "Відкриті двері" (Wildcard)

Ви додаєте на сервері заголовок: Access-Control-Allow-Origin: *

Зірочка * означає "ВСІ".

Код клієнта: Той самий. Результат: Успіх! 🎉 Чому? Сервер сказав браузеру: "Мені байдуже, хто запитує. Віддавай дані всім". Де це ок? Публічні API (погода, курси валют). Де це жахливо? У вашому приватному кабінеті користувача.


Приклад 3: "Суворий контроль" (Preflight Request)

А тепер уявіть, що ви не просто читаєте (GET), а хочете видалити щось (DELETE) або відправити JSON (Content-Type: application/json).

Тут браузер стає параноїком. Перед основним запитом він робить розвідку.

  1. Браузер (Preflight): Відправляє запит методом OPTIONS. "Агов, чи можна мені взагалі робити DELETE запит з такими заголовками?"
  2. Сервер: Має відповісти:
    • Access-Control-Allow-Methods: GET, POST, DELETE
    • Access-Control-Allow-Headers: Content-Type
  3. Браузер: "Окей, дозвіл отримано". Тільки тепер шле реальний DELETE запит.

Якщо ваш сервер не обробляє метод OPTIONS, запит впаде ще до того, як почнеться.


4. 🛠 Практична частина

Завдання для закріплення. Не читайте далі, поки не спробуєте подумки (або в коді) вирішити їх.

🔹 Завдання 1: "Знайди винного" Ви бачите помилку CORS у консолі Chrome. Ви відкриваєте Postman, робите той самий запит — і він працює! Питання: У кого проблема — у вашого коду на фронтенді, у Postman чи налаштуваннях сервера? (Підказка: згадайте, хто саме блокує запит).

🔹 Завдання 2: "Wildcard пастка" Ви налаштували сервер із заголовком Access-Control-Allow-Origin: *. Тепер ви хочете передати Cookies із авторизацією (credentials: 'include'). Запит падає з помилкою. Чому браузер забороняє * разом із Cookies? (Подумайте про безпеку: чи хочете ви, щоб БУДЬ-ЯКИЙ сайт міг відправити куки вашого користувача?)

🔹 Завдання 3: "Виправляємо Express.js" У вас є простий сервер на Node.js:

app.get('/data', (req, res) => {
  res.json({ secret: "123" });
});

Як змінити цей код, щоб дозволити доступ тільки для http://localhost:3000? (Напишіть або уявіть потрібний рядок res.setHeader(...))

🔹 Завдання 4: Міні-кейс Ви розробляєте API для мобільного додатку (iOS/Android) та веб-сайту. Чи потрібен CORS для мобільного додатку? (Підказка: Мобільний додаток — це браузер?)

🔹 Завдання 5: Preflight Ви відправляєте POST запит із заголовком Content-Type: application/json. У вкладці Network ви бачите два запити: один OPTIONS (204 No Content), другий POST (200 OK). Що станеться, якщо перший запит (OPTIONS) поверне помилку 500?


5. 💡 Мислення як у розробника

Як досвідчені інженери дивляться на CORS?

  1. Не лікуйте симптоми. Новачки часто ставлять плагін у браузер "Disable CORS", щоб "просто запрацювало".

    • Чому це погано: У вас працює, а у клієнта, який зайде на сайт — ні. Ви не вирішили проблему, ви заклеїли індикатор "Check Engine" чорною стрічкою.
  2. Безпека — це білий список. Ніколи не використовуйте * для серйозних проєктів. Тільки чіткий список дозволених доменів (whitelist).

  3. Proxy — найкращий друг. Під час розробки часто налаштовують Proxy на фронтенді (наприклад, у vite.config.js або package.json).

    • Як це працює: Браузер думає, що шле запит на localhost:3000/api, а проксі тихо перенаправляє його на localhost:8000/api. Для браузера Origin збігається — CORS не потрібен! Це елегантне рішення для локальної розробки.

6. 🧩 Підсумок

Отже, що ми сьогодні поклали собі в голову:

  1. SOP — це стіна, яка захищає користувача.
  2. CORS — це двері в цій стіні, ключі від яких лежать на Сервері.
  3. Браузер — це охоронець, який перевіряє, чи є у сервера ключі.
  4. Ви вмієте читати помилки CORS і розумієте: це не баг, це фіча безпеки.
  5. Ви знаєте, що таке OPTIONS запит (Preflight) і навіщо він "стукає" перед тим, як увійти.

Тепер ви вмієте: з'єднувати ваші фронтенди та бекенди, не лякаючись червоних повідомлень у консолі.

🔜 У наступній серії: Ми розібралися, як дозволити запити. Але як переконатися, що запит робить саме той користувач, за якого себе видає? Готуйтеся, наступна тема — Автентифікація: JWT та Сесії.

Це був CS50... тобто, це був ваш урок про CORS. До зустрічі! 👋