Jak povolit CORS pomocí HTTPOnly Cookie k zabezpečenému tokenu?

V tomto článku se podíváme, jak povolit CORS (Cross-Origin Resource Sharing) s HTTPOnly cookie pro zabezpečení našich přístupových tokenů.

V dnešní době jsou backend servery a frontend klienti nasazeni na různých doménách. Server proto musí povolit CORS, aby umožnil klientům komunikovat se serverem v prohlížečích.

Servery také implementují bezstavovou autentizaci pro lepší škálovatelnost. Tokeny jsou uloženy a spravovány na straně klienta, ale ne na straně serveru jako relace. Kvůli bezpečnosti je lepší ukládat tokeny do HTTPOnly cookies.

Table of Contents

Proč jsou požadavky Cross-Origin blokovány?

Předpokládejme, že naše frontendová aplikace je nasazena na https://app.etechblog.cz.com. Skript načtený na https://app.etechblog.cz.com může vyžadovat pouze zdroje stejného původu.

Kdykoli se pokusíme odeslat požadavek na křížový původ do jiné domény https://api.etechblog.cz.com nebo jiného portu https://app.etechblog.cz.com:3000 nebo jiného schématu http://app.etechblog.cz.com, požadavek cross-origin bude prohlížečem zablokován.

Ale proč se stejný požadavek zablokovaný prohlížečem odesílá z libovolného backendového serveru pomocí požadavku curl nebo odesílá pomocí nástrojů, jako je pošťák, bez problémů s CORS. Ve skutečnosti je to kvůli bezpečnosti, která chrání uživatele před útoky, jako je CSRF (Cross-Site Request Forgery).

  Jak hrát Company of Heroes na Linuxu

Vezměme si příklad, předpokládejme, že se některý uživatel přihlásil do svého vlastního účtu PayPal ve svém prohlížeči. Pokud můžeme odeslat požadavek na křížový původ na paypal.com ze skriptu načteného na jiné doméně malicious.com bez jakékoli chyby/blokování CORS, jako když posíláme požadavek stejného původu.

Útočníci mohou snadno odeslat svou škodlivou stránku https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account tak, že ji převedou na krátkou adresu URL, aby skryli skutečnou adresu URL. Když uživatel klikne na škodlivý odkaz, skript načtený v doméně malicious.com odešle do PayPal požadavek na křížový původ, aby převedl uživatelskou částku na účet útočníka, který bude spuštěn. Všichni uživatelé, kteří se přihlásili ke svému účtu PayPal a klikli na tento škodlivý odkaz, přijdou o své peníze. Kdokoli může snadno ukrást peníze bez znalosti uživatele účtu PayPal.

Z výše uvedeného důvodu prohlížeče blokují všechny požadavky napříč původem.

Co je CORS (Cross-Origin Resource Sharing)?

CORS je bezpečnostní mechanismus založený na hlavičkách, který server používá k tomu, aby řekl prohlížeči, aby odeslal požadavek z důvěryhodných domén.
Server s povolenými hlavičkami CORS, které se používají k tomu, aby se zabránilo blokování požadavků napříč původy prohlížeči.

Jak CORS funguje?

Protože server již definoval svou důvěryhodnou doménu ve své konfiguraci CORS. Když odešleme požadavek na server, odpověď sdělí prohlížeči, zda je požadovaná doména důvěryhodná nebo nikoli.

Existují dva typy požadavků CORS:

  • Jednoduchá žádost
  • Předletová žádost

Jednoduchá žádost:

  • Prohlížeč odešle požadavek do domény napříč původem s původem (https://app.etechblog.cz.com).
  • Server odešle zpět odpovídající odpověď s povolenými metodami a povoleným původem.
  • Po obdržení požadavku prohlížeč zkontroluje, že odeslaná hodnota záhlaví původu (https://app.etechblog.cz.com) a přijatá hodnota access-control-allow-origin (https://app.etechblog.cz.com) jsou stejné nebo divoká karta

. V opačném případě vyvolá chybu CORS.

  • Předletová žádost:
  • V závislosti na parametru vlastního požadavku z požadavku napříč původem, jako jsou metody (PUT, DELETE) nebo vlastní záhlaví nebo jiný typ obsahu atd. Prohlížeč se rozhodne odeslat požadavek OPTIONS před výstupem, aby zkontroloval, zda je odeslání skutečného požadavku bezpečné. nebo ne.

Po obdržení odpovědi (stavový kód: 204, což znamená žádný obsah), prohlížeč zkontroluje parametry access-control-allow pro aktuální požadavek. Pokud jsou parametry požadavku serverem povoleny. Odeslaný a přijatý skutečný požadavek na křížový původ

Pokud access-control-allow-origin: *, pak je odpověď povolena pro všechny zdroje. Ale není to bezpečné, pokud to nepotřebujete.

Jak povolit CORS?

  8 platforem strojového učení s nízkým kódem a bez kódu k použití

Chcete-li povolit CORS pro jakoukoli doménu, povolte hlavičky CORS, abyste povolili původ, metody, vlastní hlavičky, přihlašovací údaje atd.

  • Prohlížeč načte hlavičku CORS ze serveru a povolí aktuální požadavky od klienta až po ověření parametrů požadavku.
  • Access-Control-Allow-Origin: Chcete-li zadat přesné domény (https://app.geekflate.com, https://lab.etechblog.cz.com) nebo zástupný znak
  • Access-Control-Allow-Methods: Povolit metody HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS), které potřebujeme pouze my.
  • Access-Control-Allow-Headers: Povolit pouze konkrétní záhlaví (autorizace, csrf-token)
  • Access-Control-Allow-Credentials: Booleovská hodnota používaná k povolení křížového původu pověření (cookies, autorizační hlavička).

Access-Control-Max-Age: Řekne prohlížeči, aby na nějakou dobu uložil do mezipaměti odezvu kontroly před výstupem.

Access-Control-Expose-Headers: Zadejte záhlaví, která jsou přístupná skriptem na straně klienta.

Chcete-li povolit CORS ve webovém serveru Apache a Nginx, postupujte podle tohoto návodu.

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')
})

Povolení CORS v ExpressJS

Vezměme si příklad aplikace ExpressJS bez CORS:

npm install cors

Ve výše uvedeném příkladu jsme povolili koncový bod uživatelského rozhraní API pro metody POST, PUT, GET, ale ne metodu DELETE.

Pro snadné povolení CORS v aplikaci ExpressJS můžete nainstalovat cors

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

Access-Control-Allow-Origin

app.use(cors({
    origin: 'https://app.etechblog.cz.com'
}));

Povolení CORS pro všechny domény

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

Povolení CORS pro jednu doménu

Pokud chcete povolit CORS pro původ https://app.etechblog.cz.com a https://lab.etechblog.cz.com

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

Access-Control-Allow-Metody

Chcete-li povolit CORS pro všechny metody, vynechejte tuto možnost v modulu CORS v ExpressJS. Ale pro povolení specifických metod (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

Používá se k povolení jiných než výchozích záhlaví odesílat se skutečnými požadavky.

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

Toto vynechejte, pokud nechcete prohlížeči sdělit, aby povolil přihlašovací údaje na požádání i v případě, že parametr withCredentials je nastaven na hodnotu 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

Informovat prohlížeč, aby na určitou sekundu uložil do mezipaměti informace odezvy před výstupem. Toto vynechejte, pokud nechcete odpověď uložit do mezipaměti.

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']
}));

Odezva kontroly před výstupem uložená v mezipaměti bude v prohlížeči k dispozici po dobu 10 minut.

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

  Jak najít svůj ztracený telefon pomocí Lookout

Pokud vložíme zástupný znak

v exponovaných hlavičkách nezveřejní hlavičku Authorization. Takže musíme exponovat výslovně jako níže

Výše uvedené zobrazí všechna záhlaví a také autorizační záhlaví.

  • Co je HTTP cookie?
  • Cookie je malý kousek dat, který server odešle do klientského prohlížeče. Při pozdějších žádostech prohlížeč odešle všechny soubory cookie související se stejnou doménou na každý požadavek.
  • Cookie má svůj atribut, který lze definovat tak, aby cookie fungovalo jinak, jak potřebujeme.
  • Název Název souboru cookie.
  • hodnota: data souboru cookie odpovídající názvu souboru cookie
  • Doména: cookies budou odesílány pouze do definované domény
  • Cesta: soubory cookie odeslané pouze po definované cestě předpony URL. Předpokládejme, že jsme definovali cestu k souboru cookie jako path=’admin/‘. Soubory cookie nebyly odeslány pro adresu URL https://etechblog.cz.com/expire/, ale byly odeslány s předponou adresy URL https://etechblog.cz.com/admin/
  • Max-Age/Expires (počet v sekundách): Kdy by měla platnost cookie vypršet. Životnost souboru cookie způsobí, že cookie bude po zadané době neplatná. [Strict, Lax, None]HTTPOnly (Boolean): Backendový server může přistupovat k tomuto souboru cookie HTTPOnly, ale ne ke skriptu na straně klienta, pokud je true. Secure (Boolean): Soubory cookie se odesílají přes doménu SSL/TLS pouze v případě, že je true.sameSite(řetězec

): Používá se k povolení/omezení souborů cookie zasílaných na požadavky mezi weby. Další podrobnosti o souborech cookie sameSite viz

MDN

. Přijímá tři možnosti Strict, Lax, None. Hodnota zabezpečení souboru cookie nastavena na hodnotu true pro konfiguraci souboru cookie sameSite=None.

Proč HTTPOnly cookie pro tokeny?

Ukládání přístupového tokenu odeslaného ze serveru v úložišti na straně klienta, jako je místní úložiště, indexovaná databáze a cookie (HTTPOnly není nastaveno na hodnotu true), je zranitelnější vůči útoku XSS. Předpokládejme, že některá z vašich stránek je slabá vůči útoku XSS. Útočníci mohou zneužít uživatelské tokeny uložené v prohlížeči.

Soubory cookie HTTPOnly nastavuje/získává pouze server/backend, ale ne na straně klienta.

  • Skript na straně klienta má omezený přístup k tomuto cookie pouze HTTP. Soubory cookie HTTPOnly tedy nejsou zranitelné vůči útokům XSS a jsou bezpečnější. Protože je přístupný pouze ze serveru.
  • Povolit soubor cookie HTTPOnly v backendu s povoleným CORS
  • Povolení cookie v CORS vyžaduje níže uvedenou konfiguraci v aplikaci/serveru.
  • Nastavte hlavičku Access-Control-Allow-Credentials na hodnotu true.

Access-Control-Allow-Origin a Access-Control-Allow-Headers by neměly být zástupným znakem

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') 
}); 

.

Atribut cookie sameSite by měl být Žádný.

Chcete-li povolit hodnotu sameSite na hodnotu none, nastavte zabezpečenou hodnotu na true: Povolte backend s certifikátem SSL/TLS, aby fungoval v názvu domény.

Podívejme se na příklad kódu, který nastaví přístupový token v HTTPOnly cookie po kontrole přihlašovacích údajů.

Soubory cookie CORS a HTTPOnly můžete nakonfigurovat implementací výše uvedených čtyř kroků ve vašem backendovém jazyce a webovém serveru.

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

Můžete postupovat podle tohoto návodu pro Apache a Nginx pro povolení CORS podle výše uvedených kroků.

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

with Credentials for Cross-Origin request

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

Přihlašovací údaje (cookie, autorizace) jsou standardně odesílány s požadavkem stejného původu. Pro křížový původ musíme zadat withCredentials na true.

axios.defaults.withCredentials = true

XMLHttpRequest API

Načíst API

JQuery AjaxAxiosZávěr Doufám, že výše uvedený článek vám pomůže pochopit, jak CORS funguje, a povolit CORS pro cross-origin požadavky na serveru. Proč je ukládání souborů cookie v HTTPOnly bezpečné a jak se sCredentials používají v klientech pro požadavky napříč původem.