Як увімкнути CORS за допомогою HTTPOnly Cookie для захисту маркера?

Categories:

У цій статті ми побачимо, як увімкнути CORS (Cross-Origin Resource Sharing) із файлами cookie HTTPOnly, щоб захистити наші маркери доступу.

Зараз сервери та зовнішні клієнти розгортаються в різних доменах. Тому сервер повинен увімкнути CORS, щоб дозволити клієнтам спілкуватися з сервером у браузерах.

Крім того, сервери впроваджують автентифікацію без стану для кращої масштабованості. Токени зберігаються та обслуговуються на стороні клієнта, але не на стороні сервера, як сеанс. З міркувань безпеки краще зберігати маркери у файлах cookie HTTPOnly.

Зміст

Чому запити Cross-Origin блокуються?

Припустімо, що наш зовнішній додаток розгорнуто на https://app.techukraine.net.com. Сценарій, завантажений у https://app.techukraine.net.com, може запитувати лише ресурси того самого походження.

Кожного разу, коли ми намагаємося надіслати перехресний запит на інший домен https://api.techukraine.net.com або інший порт https://app.techukraine.net.com:3000 або іншу схему http://app.techukraine.net.com, перехресний запит буде заблоковано браузером.

Але чому той самий запит, заблокований браузером, надсилається з будь-якого внутрішнього сервера за допомогою запиту curl або надсилається за допомогою таких інструментів, як листоноша, без жодних проблем із CORS. Насправді це для безпеки, щоб захистити користувачів від таких атак, як CSRF (Cross-Site Request Forgery).

Давайте візьмемо приклад, якщо будь-який користувач увійшов у свій обліковий запис PayPal у своєму браузері. Якщо ми можемо надіслати перехресний запит до paypal.com зі сценарію, завантаженого на іншому домені malicious.com, без будь-яких помилок/блокувань CORS, як ми надсилаємо запит того самого джерела.

  Як зробити плакат за допомогою Microsoft PowerPoint

Зловмисники можуть легко надіслати свою шкідливу сторінку https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account, перетворивши її на коротку URL-адресу, щоб приховати справжню URL-адресу. Коли користувач натискає зловмисне посилання, скрипт, завантажений у домені malicious.com, надсилає перехресний запит до PayPal, щоб переказати суму користувача на обліковий запис PayPal зловмисника, і буде виконано. Усі користувачі, які ввійшли до свого облікового запису PayPal і натиснули це шкідливе посилання, втратять свої гроші. Будь-хто може легко вкрасти гроші без знання користувача облікового запису PayPal.

З наведеної вище причини браузери блокують усі перехресні запити.

Що таке CORS (Cross-Origin Resource Sharing)?

CORS — це механізм безпеки на основі заголовків, який використовується сервером, щоб наказати веб-переглядачу надіслати перехресний запит із довірених доменів.
На сервері ввімкнуто заголовки CORS, які використовуються, щоб уникнути перехресних запитів, заблокованих браузерами.

Як працює CORS?

Оскільки сервер уже визначив свій довірений домен у конфігурації CORS. Коли ми надсилаємо запит на сервер, у відповіді веб-переглядачу в заголовку буде вказано, довірений домен чи ні.

Існує два типи запитів CORS:

  • Простий запит
  • Передпольотний запит

Простий запит:

  • Браузер надсилає запит до домену між джерелами походження (https://app.techukraine.net.com).
  • Сервер надсилає відповідну відповідь із дозволеними методами та дозволеним джерелом.
  • Після отримання запиту веб-переглядач перевірить, що надіслане значення заголовка джерела (https://app.techukraine.net.com) і отримане значення access-control-allow-origin (https://app.techukraine.net.com) однакові або символ підстановки

. Інакше це викличе помилку CORS.

  • Запит перед польотом:
  • Залежно від спеціального параметра запиту з перехресного запиту, як-от методи (PUT, DELETE) або спеціальні заголовки, інший тип вмісту тощо. Браузер вирішить надіслати запит OPTIONS перед друком, щоб перевірити, чи безпечно надсилати фактичний запит чи ні.

Після отримання відповіді (код статусу: 204, що означає відсутність вмісту), браузер перевірить параметри доступу-контролю-дозволу для фактичного запиту. Якщо параметри запиту дозволені сервером. Фактичний надісланий і отриманий запит між джерелами

Якщо access-control-allow-origin: *, тоді відповідь дозволена для всіх джерел. Але це небезпечно, якщо вам це не потрібно.

Як увімкнути CORS?

Щоб увімкнути CORS для будь-якого домену, увімкніть заголовки CORS, щоб дозволити походження, методи, спеціальні заголовки, облікові дані тощо.

  • Браузер зчитує заголовок CORS із сервера та дозволяє фактичні запити від клієнта лише після перевірки параметрів запиту.
  • Access-Control-Allow-Origin: щоб указати точні домени (https://app.geekflate.com, https://lab.techukraine.net.com) або шаблон підстановки
  • Access-Control-Allow-Methods: щоб дозволити методи HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS), які потрібні лише нам.
  • Access-Control-Allow-Headers: щоб дозволити лише певні заголовки (авторизація, csrf-токен)
  • Access-Control-Allow-Credentials: логічне значення, яке використовується для дозволу перехресних облікових даних (файли cookie, заголовок авторизації).

Access-Control-Max-Age: вказує браузеру кешувати відповідь перед друком протягом деякого часу.

Access-Control-Expose-Headers: укажіть заголовки, які доступні клієнтським сценарієм.

Щоб увімкнути CORS у веб-сервері apache та Nginx, виконайте цей посібник.

const express = require('express');
const app = express()

app.get('/users', function (req, res, next) {
  res.json({msg: 'user get'})
});

app.post('/users', function (req, res, next) {
    res.json({msg: 'user create'})
});

app.put('/users', function (req, res, next) {
    res.json({msg: 'User update'})
});

app.listen(80, function () {
  console.log('CORS-enabled web server listening on port 80')
})

Увімкнення CORS у ExpressJS

Давайте візьмемо приклад програми ExpressJS без CORS:

npm install cors

У наведеному вище прикладі ми ввімкнули кінцеву точку API користувачів для методів POST, PUT, GET, але не для методу DELETE.

Щоб легко ввімкнути CORS у програмі ExpressJS, ви можете встановити cors

app.use(cors({
    origin: '*'
}));

Access-Control-Allow-Origin

app.use(cors({
    origin: 'https://app.techukraine.net.com'
}));

Увімкнення CORS для всіх доменів

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ]
}));

Увімкнення CORS для одного домену

Якщо ви хочете дозволити CORS для джерела https://app.techukraine.net.com і https://lab.techukraine.net.com

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST']
}));

Access-Control-Allow-Methods

Щоб увімкнути CORS для всіх методів, пропустіть цей параметр у модулі CORS у ExpressJS. Але для ввімкнення певних методів (GET, POST, PUT).

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token']
}));

Access-Control-Allow-Headers

Використовується для надсилання заголовків, відмінних від стандартних, із фактичними запитами.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true
}));

Access-Control-Allow-Credentials

Пропустіть це, якщо ви не хочете вказувати браузеру дозволяти облікові дані за запитом, навіть якщо для параметра withCredentials встановлено значення true.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600 
}));

Access-Control-Max-Age

  Увімкнути введення T9 на телефоні iPhone 5s [Jailbreak]

Змусити браузер кешувати інформацію відповіді перед друком у кеші протягом певної секунди. Пропустіть це, якщо ви не хочете кешувати відповідь.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600,
    exposedHeaders: ['Content-Range', 'X-Content-Range']
}));

Кешована відповідь перед випробуванням буде доступна протягом 10 хвилин у веб-переглядачі.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600,
    exposedHeaders: ['*', 'Authorization', ]
}));

Access-Control-Expose-Headers

Якщо ми поставимо символ підстановки

у exposedHeaders він не відкриє заголовок авторизації. Тож ми маємо викласти явно, як показано нижче

Наведене вище відкриє всі заголовки та заголовок авторизації.

  • Що таке HTTP cookie?
  • Файл cookie — це невеликий фрагмент даних, який сервер надсилає браузеру клієнта. У наступних запитах браузер надсилатиме всі файли cookie, пов’язані з тим самим доменом, під час кожного запиту.
  • Cookie має свій атрибут, який можна визначити, щоб змусити файл cookie працювати інакше, як нам потрібно.
  • Ім’я Ім’я файлу cookie.
  • значення: дані файлу cookie відповідно до назви файла cookie
  • Домен: файли cookie надсилатимуться лише на визначений домен
  • Шлях: файли cookie надсилаються лише після визначеного шляху префікса URL-адреси. Припустімо, якщо ми визначили наш шлях до файлів cookie як path=’admin/’. Файли cookie не надсилаються для URL-адреси https://techukraine.net.com/expire/, але надсилаються з префіксом URL-адреси https://techukraine.net.com/admin/
  • Максимальний вік/термін дії (число в секундах): коли має закінчитися термін дії файлу cookie. Термін служби cookie робить файл cookie недійсним після закінчення зазначеного часу. [Strict, Lax, None]HTTPOnly (Boolean): внутрішній сервер може отримати доступ до файлу cookie HTTPOnly, але не до сценарію на стороні клієнта, якщо значення true. Захищений (логічний): файли cookie надсилаються лише через домен SSL/TLS, якщо значення true.sameSite(рядок

): Використовується для ввімкнення/обмеження файлів cookie, які надсилаються міжсайтовими запитами. Щоб дізнатися більше про файли cookie sameSite, див

MDN

. Він приймає три параметри Strict, Lax, None. Значення безпеки файлів cookie встановлено як true для конфігурації файлів cookie sameSite=None.

  Кращі маршрутизатори DD-WRT у 2019 році для вимогливих досвідчених користувачів

Чому HTTPOnly cookie для токенів?

Зберігання маркера доступу, надісланого з сервера, у сховищі на стороні клієнта, як-от локальне сховище, індексована БД і файли cookie (для HTTPOnly не встановлено значення true), є більш вразливим до атак XSS. Припустімо, якщо якась із ваших сторінок слабка до XSS-атаки. Зловмисники можуть зловживати маркерами користувача, які зберігаються в браузері.

Файли cookie HTTPOnly встановлюються/отримуються лише сервером/сервером, але не на стороні клієнта.

  • Клієнтський сценарій обмежено доступом до файлу cookie лише HTTP. Тому файли cookie HTTPOnly не вразливі до атак XSS і є більш безпечними. Тому що він доступний лише серверу.
  • Увімкніть файли cookie HTTPOnly у підтримці CORS
  • Щоб увімкнути файли cookie в CORS, у програмі/сервері потрібна наведена нижче конфігурація.
  • Установіть для заголовка Access-Control-Allow-Credentials значення true.

Заголовки Access-Control-Allow-Origin і Access-Control-Allow-Headers не мають бути символом підстановки

const express = require('express'); 
const app = express();
const cors = require('cors');

app.use(cors({ 
  origin: [ 
    'https://app.geekflare.com', 
    'https://lab.geekflare.com' 
  ], 
  methods: ['GET', 'PUT', 'POST'], 
  allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], 
  credentials: true, 
  maxAge: 600, 
  exposedHeaders: ['*', 'Authorization' ] 
}));

app.post('/login', function (req, res, next) { 
  res.cookie('access_token', access_token, {
    expires: new Date(Date.now() + (3600 * 1000 * 24 * 180 * 1)), //second min hour days year
    secure: true, // set to true if your using https or samesite is none
    httpOnly: true, // backend only
    sameSite: 'none' // set to none for cross-request
  });

  res.json({ msg: 'Login Successfully', access_token });
});

app.listen(80, function () { 
  console.log('CORS-enabled web server listening on port 80') 
}); 

.

Атрибут файлу cookie sameSite має мати значення None.

Щоб увімкнути значення sameSite як none, установіть для безпечного значення значення true: увімкніть серверну частину із сертифікатом SSL/TLS для роботи в доменному імені.

Давайте подивимося приклад коду, який встановлює маркер доступу в HTTPOnly cookie після перевірки облікових даних для входу.

Ви можете налаштувати файли cookie CORS і HTTPOnly, виконавши наведені вище чотири кроки на мові серверної частини та веб-сервері.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.techukraine.net.com/user', true);
xhr.withCredentials = true;
xhr.send(null);

Ви можете дотримуватися цього підручника для apache та Nginx, щоб увімкнути CORS, виконавши наведені вище дії.

fetch('http://api.techukraine.net.com/user', {
  credentials: 'include'
});

з обліковими даними для запиту Cross-Origin

$.ajax({
   url: 'http://api.techukraine.net.com/user',
   xhrFields: {
      withCredentials: true
   }
});

Облікові дані (файли cookie, авторизація) за замовчуванням надсилаються разом із запитом того самого джерела. Для перехресного походження ми маємо вказати параметр withCredentials у значення true.

axios.defaults.withCredentials = true

API XMLHttpRequest

API Fetch

JQuery AjaxАксіосВисновок Сподіваюся, наведена вище стаття допоможе вам зрозуміти, як працює CORS, і ввімкнути CORS для перехресних запитів на сервері. Чому зберігання файлів cookie в HTTPOnly є безпечним і як з обліковими даними, які використовуються клієнтами для перехресних запитів.