Cum se activează CORS cu HTTPOnly Cookie pentru a securiza simbolul?

În acest articol, vedem cum să activăm CORS (Cross-Origin Resource Sharing) cu cookie HTTPOnly pentru a ne securiza token-urile de acces.

În prezent, serverele backend și clienții frontend sunt implementați pe diferite domenii. Prin urmare, serverul trebuie să activeze CORS pentru a permite clienților să comunice cu serverul pe browsere.

De asemenea, serverele implementează autentificarea fără stat pentru o scalabilitate mai bună. Tokenurile sunt stocate și menținute pe partea clientului, dar nu pe partea serverului, precum sesiune. Pentru securitate, este mai bine să stocați token-urile în module cookie HTTPOnly.

Cuprins

De ce sunt blocate solicitările Cross-Origin?

Să presupunem că aplicația noastră frontală a fost implementată la https://app.tipstrick.ro.com. Un script încărcat în https://app.tipstrick.ro.com poate solicita doar resurse de aceeași origine.

Ori de câte ori încercăm să trimitem o cerere de origine încrucișată către un alt domeniu https://api.tipstrick.ro.com sau alt port https://app.tipstrick.ro.com:3000 sau altă schemă http://app.tipstrick.ro.com, cererea de origine încrucișată va fi blocată de browser.

  Un ghid complet pentru procesul și practicile de management al lansărilor

Dar de ce aceeași cerere blocată de browser să fie trimisă de pe orice server backend folosind cerere curl sau trimisă folosind instrumente precum poștașul fără nicio problemă CORS. Este de fapt pentru securitate pentru a proteja utilizatorii de atacuri precum CSRF (Cross-Site Request Forgery).

Să luăm un exemplu, să presupunem că vreun utilizator s-a autentificat în propriul cont PayPal în browser. Dacă putem trimite o solicitare cu origini încrucișate către paypal.com dintr-un script încărcat pe alt domeniu malicious.com fără nicio eroare/blocare CORS, așa cum trimitem cererea de aceeași origine.

Atacatorii își pot trimite cu ușurință pagina rău intenționată https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account, transformând-o în short-URL pentru a ascunde adresa URL reală. Când utilizatorul face clic pe un link rău intenționat, scriptul încărcat în domeniul malicious.com va trimite o solicitare de origine încrucișată către PayPal pentru a transfera suma utilizatorului în contul PayPal al atacatorului care va fi executat. Toți utilizatorii care s-au conectat la contul lor PayPal și au făcut clic pe acest link rău intenționat își vor pierde banii. Oricine poate fura cu ușurință bani fără cunoștințele utilizatorului unui cont PayPal.

Din motivul de mai sus, browserele blochează toate solicitările de origine încrucișată.

Ce este CORS (Cross-Origin Resource Sharing)?

CORS este un mecanism de securitate bazat pe antet folosit de server pentru a spune browserului să trimită o solicitare de origine încrucișată de la domenii de încredere.
Serverul activat cu anteturi CORS utilizate pentru a evita solicitările de origine încrucișată blocate de browsere.

Cum funcționează CORS?

Deoarece serverul și-a definit deja domeniul de încredere în configurația sa CORS. Când trimitem o solicitare către server, răspunsul va spune browserului că domeniul solicitat este de încredere sau nu în antetul său.

Există două tipuri de solicitări CORS:

  • Cerere simplă
  • Solicitare preflight

Cerere simplă:

  • Browserul trimite cererea către un domeniu cross-origin cu origin(https://app.tipstrick.ro.com).
  • Serverul trimite înapoi răspunsul corespunzător cu metodele permise și originea permisă.
  • După primirea cererii, browserul va verifica valoarea antetului de origine trimisă (https://app.tipstrick.ro.com) și valoarea primită pentru controlul accesului-allow-origin (https://app.tipstrick.ro.com) sunt aceleași sau wildcard

. În caz contrar, va genera o eroare CORS.

  • Solicitare preflight:
  • În funcție de parametrul de solicitare personalizat din cererea de origine încrucișată, cum ar fi metode (PUT, DELETE) sau anteturi personalizate sau diferite tipuri de conținut, etc. Browserul va decide să trimită o solicitare OPȚIUNI de verificare pentru a verifica dacă cererea reală este sigură de trimis sau nu.

După primirea răspunsului (codul de stare: 204, ceea ce înseamnă că nu există conținut), browserul va verifica parametrii de acces-control-permitere pentru cererea reală. Dacă parametrii de solicitare sunt permisi de server. Solicitarea reală cu origini încrucișate trimisă și primită

  Cum să instalezi aplicații direct pe Apple Watch

Dacă acces-control-allow-origin: *, atunci răspunsul este permis pentru toate originile. Dar nu este sigur decât dacă aveți nevoie de el.

Cum se activează CORS?

Pentru a activa CORS pentru orice domeniu, activați antetele CORS pentru a permite originea, metodele, anteturile personalizate, acreditările etc.

  • Browserul citește antetul CORS de pe server și permite cererile reale de la client numai după verificarea parametrilor cererii.
  • Access-Control-Allow-Origin: Pentru a specifica domeniile exacte (https://app.geekflate.com, https://lab.tipstrick.ro.com) sau wildcard
  • Acces-Control-Permite-Metode: Pentru a permite metodele HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) de care avem nevoie doar.
  • Access-Control-Allow-Headers: pentru a permite numai anumite antete (autorizare, csrf-token)
  • Access-Control-Allow-Credentials: valoare booleană utilizată pentru a permite acreditările de origine încrucișată (cookie-uri, antet de autorizare).

Access-Control-Max-Age: Spune browserului să memoreze în cache răspunsul preflight pentru ceva timp.

Access-Control-Expose-Headers: specificați anteturile care sunt accesibile prin script-ul clientului.

Pentru a activa CORS în apache și serverul web Nginx, urmați acest tutorial.

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

Activarea CORS în ExpressJS

Să luăm un exemplu de aplicație ExpressJS fără CORS:

npm install cors

În exemplul de mai sus, am activat terminalul API al utilizatorilor pentru metodele POST, PUT, GET, dar nu și metoda DELETE.

Pentru activarea simplă a CORS în aplicația ExpressJS, puteți instala cors

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

Acces-Control-Permite-Origine

app.use(cors({
    origin: 'https://app.tipstrick.ro.com'
}));

Activarea CORS pentru toate domeniile

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

Activarea CORS pentru un singur domeniu

Dacă doriți să permiteți CORS pentru origine https://app.tipstrick.ro.com și https://lab.tipstrick.ro.com

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

Acces-Control-Permite-Metode

Pentru a activa CORS pentru toate metodele, omiteți această opțiune în modulul CORS din ExpressJS. Dar pentru activarea unor metode specifice (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']
}));

Acces-Control-Permite-anteturi

Folosit pentru a permite trimiterea antetelor, altele decât cele implicite, împreună cu solicitările reale.

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

Acces-Control-Permite-Acreditări

Omiteți acest lucru dacă nu doriți să spuneți browserului să permită acreditările la cerere, chiar și atunci când withCredentials este setat la adevărat.

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

Acces-Control-Max-Age

Pentru a intima browserul să memoreze în cache informațiile de răspuns preflight în cache pentru o secundă specificată. Omiteți acest lucru dacă nu doriți să stocați în cache răspunsul.

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

Răspunsul preflight memorat în cache va fi disponibil timp de 10 minute în browser.

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

Acces-Control-Expunere-anteturi

  6 moduri utile de a șterge aplicații de pe iPhone

Dacă punem wildcard

în exposedHeaders, nu va expune antetul Authorization. Deci trebuie să expunem explicit ca mai jos

Cele de mai sus vor expune toate anteturile și antetul de autorizare.

  • Ce este un cookie HTTP?
  • Un cookie este o mică bucată de date pe care serverul o va trimite browserului clientului. La solicitările ulterioare, browserul va trimite toate cookie-urile aferente aceluiași domeniu la fiecare solicitare.
  • Cookie-ul are atributul său, care poate fi definit pentru a face un cookie să funcționeze diferit după cum avem nevoie.
  • Nume Numele cookie-ului.
  • valoare: datele cookie-ului respectiv numele cookie-ului
  • Domeniu: cookie-urile vor fi trimise numai către domeniul definit
  • Cale: cookie-uri trimise numai după calea prefixului URL definită. Să presupunem că am definit calea cookie-ului, cum ar fi calea=’admin/’. Cookie-urile nu sunt trimise pentru adresa URL https://tipstrick.ro.com/expire/, dar sunt trimise cu prefixul URL https://tipstrick.ro.com/admin/
  • Max-Age/Expires (număr în secundă): când ar trebui să expire cookie-ul. O durată de viață a cookie-ului face cookie-ul invalid după timpul specificat. [Strict, Lax, None]HTTPOnly(Boolean): serverul de backend poate accesa acel cookie HTTPOnly, dar nu și script-ul clientului atunci când este adevărat. Securizat (boolean): cookie-urile trimise pe un domeniu SSL/TLS numai atunci când sunt adevărate.sameSite(șir

): Folosit pentru a activa/restricționa cookie-urile trimise la solicitările între site-uri. Pentru a afla mai multe detalii despre cookie-uri sameSite vezi

MDN

. Acceptă trei opțiuni Strict, Lax, None. Valoarea securizată a cookie-urilor setată la true pentru configurația cookie sameSite=Niciuna.

De ce cookie HTTPOnly pentru token-uri?

Stocarea jetonului de acces trimis de la server în stocarea pe partea client, cum ar fi stocarea locală, DB indexat și cookie-ul (HTTPOnly nu este setat la adevărat) este mai vulnerabilă la atacul XSS. Să presupunem că oricare dintre paginile dvs. este slabă la un atac XSS. Atacatorii pot folosi greșit jetoanele de utilizator stocate în browser.

Cookie-urile HTTPOnly sunt setate/obținute numai de server/backend, dar nu și de partea clientului.

  • Scriptul pe partea clientului este restricționat pentru a accesa acel cookie numai HTTP. Prin urmare, cookie-urile HTTPOnly nu sunt vulnerabile la atacurile XSS și sunt mai sigure. Pentru că este accesibil doar de către server.
  • Activați cookie-ul HTTPOnly în backend-ul compatibil CORS
  • Activarea cookie-urilor în CORS necesită configurația de mai jos în aplicație/server.
  • Setați antetul Access-Control-Allow-Credentials la adevărat.

Acces-Control-Allow-Origin și Access-Control-Allow-Headers nu ar trebui să fie un wildcard

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

.

Atributul cookie sameSite ar trebui să fie Nici unul.

Pentru a activa valoarea sameSite la niciunul, setați valoarea sigură la true: Activați backend-ul cu certificat SSL/TLS pentru a funcționa în numele domeniului.

Să vedem un exemplu de cod care setează un token de acces în modul cookie HTTPOnly după verificarea acreditărilor de conectare.

Puteți configura modulele cookie CORS și HTTPOnly prin implementarea celor patru pași de mai sus în limba și serverul dvs. web.

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

Puteți urma acest tutorial pentru apache și Nginx pentru activarea CORS urmând pașii de mai sus.

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

cuCredentials pentru cerere Cross-Origin

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

Acreditări (cookie, autorizare) trimise implicit cu aceeași cerere de origine. Pentru origini încrucișate, trebuie să specificăm withCredentials la adevărat.

axios.defaults.withCredentials = true

API XMLHttpRequest

Preluați API-ul

JQuery AjaxAxiosConcluzie Sper că articolul de mai sus vă ajută să înțelegeți cum funcționează CORS și să activați CORS pentru cererile de origine încrucișată pe server. De ce stocarea cookie-urilor în HTTPOnly este securizată și cum se utilizează Credentials în clienți pentru cererile de origine încrucișată.