Hur aktiverar man CORS med HTTPOnly Cookie för att säkra token?

I den här artikeln ser vi hur du aktiverar CORS (Cross-Origin Resource Sharing) med HTTPOnly cookie för att säkra våra åtkomsttokens.

Nuförtiden är backend-servrar och frontend-klienter utplacerade på olika domäner. Därför måste servern aktivera CORS för att tillåta klienter att kommunicera med servern i webbläsare.

Dessutom implementerar servrar tillståndslös autentisering för bättre skalbarhet. Tokens lagras och underhålls på klientsidan, men inte på serversidan som sessionen. Av säkerhetsskäl är det bättre att lagra tokens i HTTPOnly cookies.

Innehållsförteckning

Varför blockeras Cross-Origin-förfrågningar?

Låt oss anta att vår frontend-applikation distribueras på https://app.adminvista.com.com. Ett skript laddat i https://app.adminvista.com.com kan bara begära resurser med samma ursprung.

Närhelst vi försöker skicka en begäran om korsuppkomst till en annan domän https://api.adminvista.com.com eller en annan port https://app.adminvista.com.com:3000 eller ett annat schema http://app.adminvista.com.com, cross-origin begäran kommer att blockeras av webbläsaren.

Men varför samma begäran som blockerats av webbläsaren skickas från valfri backend-server med curl-begäran eller skickas med hjälp av verktyg som brevbäraren utan några CORS-problem. Det är faktiskt för säkerheten att skydda användare från attacker som CSRF (Cross-Site Request Forgery).

Låt oss ta ett exempel, anta om någon användare loggat in på sitt eget PayPal-konto i sin webbläsare. Om vi ​​kan skicka en cross-origin-begäran till paypal.com från ett skript laddat på en annan domän malicious.com utan något CORS-fel/blockering som att vi skickar samma ursprungsbegäran.

Angripare kan enkelt skicka sin skadliga sida https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account genom att konvertera den till kort webbadress för att dölja den faktiska webbadressen. När användaren klickar på en skadlig länk kommer skriptet som laddas i domänen malicious.com att skicka en begäran om korsuppkomst till PayPal om att överföra användarbeloppet till angriparens PayPal-konto som kommer att köras. Alla användare som har loggat in på sitt PayPal-konto och klickat på den här skadliga länken kommer att förlora sina pengar. Vem som helst kan enkelt stjäla pengar utan användarkännedom om ett PayPal-konto.

Av ovanstående anledning blockerar webbläsare alla förfrågningar om gränsöverskridande ursprung.

Vad är CORS (Cross-Origin Resource Sharing)?

CORS är en header-baserad säkerhetsmekanism som används av servern för att tala om för webbläsaren att skicka en kors-ursprungsförfrågan från betrodda domäner.
Servern aktiverad med CORS-rubriker som används för att undvika förfrågningar som blockeras av webbläsare.

Hur fungerar CORS?

Eftersom servern redan har definierat sin betrodda domän i sin CORS-konfiguration. När vi skickar en förfrågan till servern kommer svaret att tala om för webbläsaren att den begärda domänen är betrodd eller inte i dess rubrik.

Det finns två typer av CORS-förfrågningar:

  • Enkel begäran
  • Preflight-förfrågan

Enkel begäran:

  • Webbläsaren skickar begäran till en domän med ursprung (https://app.adminvista.com.com).
  • Servern skickar tillbaka motsvarande svar med tillåtna metoder och tillåtet ursprung.
  • Efter att ha mottagit begäran kommer webbläsaren att kontrollera att det skickade ursprungshuvudvärdet (https://app.adminvista.com.com) och det mottagna access-control-allow-origin-värdet (https://app.adminvista.com.com) är desamma eller jokertecken

. Annars kommer det att ge ett CORS-fel.

  • Preflight-förfrågan:
  • Beroende på den anpassade begäran-parametern från korsorigin-begäran som metoder (PUT, DELETE) eller anpassade rubriker eller annan innehållstyp, etc. Webbläsaren kommer att besluta att skicka en preflight OPTIONS-begäran för att kontrollera om den faktiska begäran är säker att skicka eller inte.

Efter att ha mottagit svaret (statuskod: 204, vilket betyder inget innehåll), kommer webbläsaren att söka efter parametrarna för åtkomstkontroll-tillåt för den faktiska begäran. Om förfrågningsparametrarna tillåts av servern. Den faktiska korsoriginella begäran som skickas och tas emot

Om access-control-allow-origin: *, är svaret tillåtet för alla ursprung. Men det är inte säkert om du inte behöver det.

Hur aktiverar man CORS?

För att aktivera CORS för vilken domän som helst, aktivera CORS-rubriker för att tillåta ursprung, metoder, anpassade rubriker, autentiseringsuppgifter, etc.

  • Webbläsaren läser CORS-huvudet från servern och tillåter faktiska förfrågningar från klienten endast efter att ha verifierat förfrågningsparametrar.
  • Access-Control-Allow-Origin: För att ange exakta domäner (https://app.geekflate.com, https://lab.adminvista.com.com) eller jokertecken
  • Access-Control-Allow-Methods: För att tillåta HTTP-metoderna (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) som bara vi behöver.
  • Access-Control-Allow-Headers: För att endast tillåta specifika rubriker (auktorisering, csrf-token)
  • Access-Control-Allow-Credentials: Booleskt värde som används för att tillåta cross-origin-credentials (cookies, auktoriseringshuvud).

Access-Control-Max-Age: Instruerar webbläsaren att cachelagra preflight-svaret under en tid.

Access-Control-Expose-Headers: Ange rubriker som är tillgängliga med skript på klientsidan.

För att aktivera CORS i apache och Nginx webbserver, följ denna handledning.

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

Aktiverar CORS i ExpressJS

Låt oss ta ett exempel på ExpressJS-app utan CORS:

npm install cors

I exemplet ovan har vi aktiverat användarnas API-slutpunkt för POST, PUT, GET-metoder men inte DELETE-metoden.

För att enkelt aktivera CORS i ExpressJS-appen kan du installera cors

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

Access-Control-Allow-Origin

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

Aktiverar CORS för alla domäner

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

Aktiverar CORS för en enda domän

Om du vill tillåta CORS för ursprung https://app.adminvista.com.com och https://lab.adminvista.com.com

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

Access-Control-Allow-Methods

För att aktivera CORS för alla metoder, utelämna detta alternativ i CORS-modulen i ExpressJS. Men för att aktivera specifika metoder (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

Används för att tillåta andra rubriker än standard att skicka med faktiska förfrågningar.

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-Redigeringar

Utelämna detta om du inte vill tala om för webbläsaren att tillåta referenser på begäran även om withCredentials är satt till 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

Att uppmana webbläsaren att cachelagra preflight-svarsinformationen i cachen under en angiven sekund. Uteslut detta om du inte vill cachelagra svaret.

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

Det cachade preflight-svaret kommer att vara tillgängligt i 10 minuter i webbläsaren.

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

Om vi ​​sätter jokertecknet

i exposedHeaders kommer det inte att exponera auktoriseringshuvudet. Så vi måste explicit explicit som nedan

Ovanstående kommer också att exponera alla rubriker och auktoriseringsrubriker.

  • Vad är en HTTP-cookie?
  • En cookie är en liten bit data som servern skickar till klientens webbläsare. Vid senare förfrågningar kommer webbläsaren att skicka alla cookies relaterade till samma domän vid varje begäran.
  • Cookie har sitt attribut, som kan definieras för att få en cookie att fungera annorlunda som vi behöver.
  • Namn Namn på kakan.
  • värde: data för cookie respektive cookie-namn
  • Domän: cookies skickas endast till den definierade domänen
  • Sökväg: cookies skickas endast efter den definierade sökvägen för URL-prefixet. Anta att om vi har definierat vår cookie-sökväg som path=’admin/’. Cookies skickas inte för webbadressen https://adminvista.com.com/expire/ utan skickas med URL-prefix https://adminvista.com.com/admin/
  • Max-Age/Expires(antal i sekund): När ska cookien förfalla. En livstid av cookien gör cookien ogiltig efter den angivna tiden. [Strict, Lax, None]HTTPOnly(Boolean): Backend-servern kan komma åt den HTTPOnly-cookien men inte skriptet på klientsidan när det är sant. Säker (boolesk): Cookies skickas endast över en SSL/TLS-domän när sant.sameSite(sträng

): Används för att aktivera/begränsa cookies som skickas över förfrågningar mellan webbplatser. För mer information om cookies se sameSite

MDN

. Den accepterar tre alternativ Strict, Lax, None. Cookie säkert värde satt till sant för cookie-konfigurationen sameSite=Ingen.

Varför HTTPOnly cookie för tokens?

Att lagra åtkomsttoken som skickats från servern i lagring på klientsidan som lokal lagring, indexerad DB och cookie (HTTTPOnly inte satt till true) är mer sårbara för XSS-attack. Anta att om någon av dina sidor är svag för en XSS-attack. Angripare kan missbruka användartokens som lagras i webbläsaren.

Endast HTTP-cookies sätts/getas av servern/backend men inte på klientsidan.

  • Skript på klientsidan är begränsat för åtkomst till den endast HTTP-cookien. Så HTTPOnly cookies är inte sårbara för XSS-attacker och är säkrare. Eftersom det bara är tillgängligt av servern.
  • Aktivera HTTPOnly-cookie i CORS-aktiverad backend
  • Aktivering av Cookie i CORS kräver konfigurationen nedan i applikationen/servern.
  • Ställ in Access-Control-Allow-Credentials-huvudet till sant.

Access-Control-Allow-Origin och Access-Control-Allow-Headers ska inte vara ett jokertecken

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-attribut ska vara None.

För att aktivera sameSite-värdet till none, ställ in det säkra värdet till true: Aktivera backend med SSL/TLS-certifikat för att fungera i domännamnet.

Låt oss se en exempelkod som ställer in en åtkomsttoken i HTTPOnly-cookien efter att ha kontrollerat inloggningsuppgifterna.

Du kan konfigurera CORS- och HTTPOnly-cookies genom att implementera ovanstående fyra steg i ditt backend-språk och webbserver.

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

Du kan följa denna handledning för apache och Nginx för att aktivera CORS genom att följa stegen ovan.

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

med inloggningsuppgifter för Cross-Origin-begäran

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

Inloggningsuppgifter (cookie, auktorisering) skickas som standard med begäran om samma ursprung. För cross-origin måste vi specificera withCredentials till true.

axios.defaults.withCredentials = true

XMLHttpRequest API

Hämta API

JQuery AjaxAxiosSlutsats Jag hoppas att artikeln ovan hjälper dig att förstå hur CORS fungerar och aktivera CORS för förfrågningar om gränsöverskridande ursprung i servern. Varför det är säkert att lagra cookies i HTTPOnly och hur med inloggningsuppgifter som används i klienter för förfrågningar med flera ursprung.