Att flytta administrationsgränssnittet till admin.example.com är en reell förbättring: det håller admin-cookies borta från offentliga sidor, ger de två applikationerna egna cacheminnen och låter dig rikta en strängare nätverkspolicy mot ett enda värdnamn. Men det är inte en CSRF-kontroll, och det gör inte koden på den offentliga webbplatsen säker att lämna öppen framför en inloggad administratör. Uppdelningen ändrar vad webbläsaren ser som en gräns, inte vad servern kontrollerar, så gör dessa fyra kontroller innan du säger att det är klart.

Läs origin och webbplats som två olika ord

En origin är schema, värd och port, så https://www.example.com och https://admin.example.com är olika origins. En webbplats, i SameSite-bemärkelse, är schema plus registrerbar domän, så de två värdnamnen är vanligen samma webbplats. Den skillnaden är hela fällan: attributet SameSite hjälper dig inte mellan systerunderdomäner, eftersom webbläsaren inte alls betraktar begäran som korsande webbplats. Rikta administrationsgränssnittet mot en verkligen annan registrerbar domän, till exempel admin-example.net, och begäran blir faktiskt korsande, och det är där SameSite=Lax eller Strict börjar göra arbete du kan lita på.

Testa det i webbläsaren i stället för att resonera om det.

Ladda den offentliga webbplatsen, öppna utvecklarverktygen och se vilka cookies webbläsaren bifogar en begäran mot admin-värden. Om cookien saknar attributet Domain gäller den bara värden och stannar på sitt eget namn; om den bär Domain=example.com reser den till varje syster, och den nya underdomänen gav dig ingenting för den cookien.

Skilj på att läsa svaret och att skicka begäran

Samma-origin-policyn begränsar läsning av svar mellan origins. Den stoppar inte att en begäran skickas, och den hindrar inte ett formulär från att bära autentiseringsuppgifter som webbläsaren redan har. En enkel begäran, med formulärinnehållstyp eller en vanlig GET, levereras utan förhandskontroll; CORS avgör sedan om det anropande skriptet får läsa svaret. CSRF lever helt på sändarsidan.

Därför behöver servern en uttrycklig kontroll för tillståndsändrande operationer. En synkroniseringstoken bunden till sessionen, eller en cookie med dubbel insändning som jämförs på servern, täcker fallet; en Origin- eller Referer-jämförelse är värd att lägga till som en andra port men inte som den enda, eftersom inte varje begäran bär huvudet och inte varje proxy bevarar det. OWASPs vägledning för att förebygga CSRF behandlar SameSite som ett lager bland flera just av denna anledning.

Avgör vad nätverksporten faktiskt bevisar

En lista över tillåtna VPN-utgångar framför admin-värden är god kontroll och ett svagt identitetspåstående. Den bevisar att begäran kom från en adress som VPN delar ut, som alla på den utgången kan dela, och den säger ingenting om vilken person eller enhet som står bakom. Behandla den som ett inträdesfilter, inte som autentisering.

Håll den oberoende av kontrollerna på begärandenivå. Om listan är det enda mellan en angripare och en tillståndsändrande slutpunkt tar en felkonfigurerad rutt, en split-tunnel-klient eller en lånad bärbar dator bort kontrollen helt.

Logga också avvisningar utanför de förväntade intervallen. En våg av dem är den mest användbara signalen om att någon undersöker gränsen du just byggt, och tystnad är signalen om att filtret inte nås alls.

Håll cookies, inloggning och auktorisering uttryckliga

Cookiens omfång avgör det mesta av resultatet. En cookie för föräldradomänen skickas till admin-värden, så en skriptinjektion på den offentliga webbplatsen kan agera med en administratörs session; en cookie bara för värden kan inte det. Föredra formen bara för värden, lägg till attributet Secure och använd prefixet __Host- där plattformen stöder det, eftersom prefixet kräver Secure, Path=/ och inget Domain-attribut. Läs svarshuvudet i stället för cookiekrukan: Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax, utan Domain-attribut. En webbläsare kastar en __Host--cookie med Domain, så en cookie som fortfarande syns på systervärdar är bevis för att prefixet aldrig tillämpades.

Håll sedan auktoriseringen på servern, per begäran, på varje administrativ slutpunkt, inte bara vid inloggning. En begäran från ett tillåtet nätverk måste fortfarande autentiseras och auktoriseras för operationen den begär; värdnamnet är ingen aktör. Om den offentliga och den administrativa applikationen delar ett inloggningsflöde eller ett sessionslager, skriv ned det förhållandet, eftersom det är den kortaste vägen från ett fel på den offentliga webbplatsen till en administrativ åtgärd.

Kontrollera gränsen igen efter uppdelningen

Kör de negativa testerna, inte bara den lyckliga vägen: ett korsande formulär utan token ska avvisas, en token från en annan session ska avvisas, och ingen GET får ändra tillstånd. Kontrollera cookie-attributen i utvecklarverktygen, bekräfta att Origin-kontrollen slår till vid en begäran som inte stämmer, och prova admin-värden utanför VPN-intervallet för att se filtret verka.

Inget av detta tar bort ett XSS-fel inne i själva adminapplikationen. Ett separat värdnamn är en isoleringsgräns på webbläsarsidan med reellt värde, och det ersätter inte att förhindra osäker kodkörning eller att skydda begäranden på serversidan. Efter uppdelningen är listan kortare än den ser ut: egen origin, cookies bara för värden, en token vid varje ändring, ett inträdesfilter du inte litar på som identitet, och auktorisering beslutad per begäran.

Relaterade artiklar