Säkra molnbaserade applikationer med OAuth 2.0 och OpenID Connect
En komplett guide för att säkra dina molnapplikationer med OAuth 2.0 och OpenID Connect och hur man erbjuder en fantastisk användarupplevelse med autentisering och auktorisering.
En komplett guide för att säkra dina molnapplikationer med OAuth 2.0 och OpenID Connect och hur man erbjuder en fantastisk användarupplevelse med autentisering och auktorisering.
Molnbaserade applikationer är trenden nuförtiden. Även om applikationstypen varierar (webb, mobil, desktop, etc.), har de alla en molnbakgrund som tillhandahåller tjänster som lagring, beräkning och databaser. Oftast behöver dessa applikationer autentisera användare och auktorisera dem för att få tillgång till vissa resurser.
Även om egentillverkade autentiserings- och auktoriseringsmekanismer är möjliga, har säkerhet blivit en av de främsta bekymren vid utveckling av molnapplikationer. Lyckligtvis har vår bransch stridsprövade standarder som OAuth 2.0 och OpenID Connect för att hjälpa oss att implementera säker autentisering och auktorisering.
Detta inlägg har följande antaganden:
Ja, "hört" är tillräckligt för både 2 och 3. Detta inlägg kommer att använda exempel från verkligheten för att förklara begrepp och illustrera processen med diagram. Låt oss börja!
Om du är bekant med OAuth 2.0 och OpenID Connect kan du också fortsätta läsa eftersom vi kommer att täcka några exempel från verkligheten i detta avsnitt; om du är ny till dessa standarder är det också säkert att fortsätta eftersom vi kommer introducera dem på ett enkelt sätt.
OAuth 2.0 är ett auktoriseringsramverk som tillåter en applikation att få begränsad tillgång till skyddade resurser på en annan applikation å en användares eller applikationens vägnar. De flesta populära tjänster som Google, Facebook och GitHub använder OAuth 2.0 för social inloggning (t.ex. "Logga in med Google").
Till exempel, du har en webbapplikation MyApp som vill ha tillgång till användarens Google Drive. Istället för att be användaren om deras Google Drive-referenser kan MyApp använda OAuth 2.0 för att begära tillgång till Google Drive å användarens vägnar. Här är ett förenklat flöde:
I detta flöde ser MyApp aldrig användarens Google Drive-referenser. Istället får den en åtkomsttoken från Google som tillåter den att få tillgång till Google Drive å användarens vägnar.
I OAuth 2.0-termer är MyApp kunden, Google är både auktoriseringsservern och resursservern för enkelhetens skull. I verkligheten har vi ofta separata auktoriserings- och resursservrar för att erbjuda en enkel inloggning (SSO) upplevelse. Till exempel, Google är auktoriseringsservern och det kan ha flera resursservrar som Google Drive, Gmail och YouTube.
Observera att det faktiska auktoriseringsflödet är mer komplext än detta. OAuth 2.0 har olika bidragstyper, omfattningar och andra begrepp som du bör vara medveten om. Vi lämnar det åt sidan för nu och går vidare till OpenID Connect.
OAuth 2.0 är bra för auktorisering, men du kanske märker att det inte har ett sätt att identifiera användaren (dvs. autentisering). OpenID Connect är ett identitetslager överst på OAuth 2.0 som lägger till autentiseringsfunktioner.
I exemplet ovan behöver MyApp veta vem användaren är innan den initierar auktoriseringsflödet. Observera att det finns två användare inblandade här: användaren av MyApp och användaren av Google Drive. I detta fall behöver MyApp veta användaren av sin egen applikation.
Låt oss se ett enkelt exempel, förutsatt att användare kan logga in på MyApp med användarnamn och lösenord:
Eftersom vi autentiserar användaren av vår egen applikation är det vanligtvis inte nödvändigt att be om tillstånd som Google gjorde i OAuth 2.0-flödet. Under tiden behöver vi något som kan identifiera användaren. OpenID Connect introducerar begrepp som ID-token och användarinfoändpunkt för att hjälpa oss med det.
Du kan märka att identitetsleverantören (IdP) är en ny fristående deltagare i flödet. Det är detsamma som auktoriseringsservern i OAuth 2.0, men för bättre tydlighet använder vi termen IdP för att visa att det är ansvaret för användarautentisering och identitetshantering.
När ditt företag växer kan du ha flera applikationer som delar samma användardatabas. Precis som OAuth 2.0 tillåter OpenID Connect dig att ha en enda auktoriseringsserver som kan autentisera användare för flera applikationer. Om användaren redan är inloggad i en applikation behöver de inte ange sina referenser igen när en annan applikation dirigerar dem till IdP. Flödet kan ske automatiskt utan användarinteraktion. Detta kallas enkel inloggning (SSO).
Återigen är detta ett högst förenklat flöde och det finns fler detaljer under ytan. För nu går vi vidare till nästa avsnitt för att undvika informationsöverbelastning.
I föregående avsnitt använde vi webbapplikationer som exempel medan världen är mer diversifierad än så. För en identitetsleverantör spelar det exakta programspråket, ramverket eller plattformen du använder egentligen ingen roll. I praktiken är en märkbar skillnad om applikationen är en offentlig klient eller en privat (betrodd) klient:
Med detta i åtanke, låt oss se hur OAuth 2.0 och OpenID Connect kan användas i olika applikationstyper.
"Applikation" och "klient" kan användas omväxlande i denna posts sammanhang.
Applikationen körs på en server och betjänar HTML-sidor till användare. Många populära webbramverk som Express.js, Django och Ruby on Rails faller in i denna kategori; och backend-för-front-ramverk (BFF) som Next.js och Nuxt.js är också inkluderade. Dessa applikationer har följande egenskaper:
Under tiden kan applikationen behöva få tillgång till andra interna API-tjänster i en mikrotjänstarkitektur; eller det är en monolitisk applikation som behöver åtkomstkontroll för olika delar av applikationen. Vi kommer att diskutera detta i avsnittet "Skydda din API".
Applikationen körs i en användares webbläsare och kommunicerar med servern via API:er. React, Angular och Vue.js är populära ramverk för att bygga SPAs. Dessa applikationer har följande egenskaper:
Vanligtvis behöver SPAs få tillgång till andra API-tjänster för datainsamling och uppdatering. Vi kommer att diskutera detta i avsnittet "Skydda din API".
Applikationen körs på en mobil enhet (iOS, Android, etc.) och kommunicerar med servern via API:er. I de flesta fall har dessa applikationer samma egenskaper som SPAs.
Maskin-till-maskin applikationer är klienter som körs på en server (maskin) och kommunicerar med andra servrar. Dessa applikationer har följande egenskaper:
När man får tillgång till andra tjänster kan applikationen behöva tillhandahålla åtkomsttoket i begäransrubriken. Vi kommer att diskutera detta i avsnittet "Skydda din API".
Applikationen körs på en IoT-enhet (t.ex. smarta hemanordningar, wearables, etc.) och kommunicerar med servern via API:er. Dessa applikationer har följande egenskaper:
När man kommunicerar med servern kan enheten behöva tillhandahålla åtkomsttoken i begäransrubriken. Vi kommer att diskutera detta i avsnittet "Skydda din API".
Med OpenID Connect är det möjligt att identifiera användaren och hämta användarspecifik data via ID-tokens eller användarinfoändpunkter. Denna process kallas autentisering. Men du kanske inte vill exponera alla dina resurser till alla autentiserade användare, till exempel, endast administratörer kan få tillgång till användarhanteringssidan.
Detta är där auktorisering spelar en roll. Kom ihåg att OAuth 2.0 är ett auktoriseringsramverk, och OpenID Connect är ett identitetslager överst på OAuth 2.0; vilket innebär att du också kan använda OAuth 2.0 när OpenID Connect redan är på plats.
Låt oss minnas exemplet vi använde i avsnittet "OAuth 2.0": MyApp vill få tillgång till användarens Google Drive. Det är inte praktiskt att låta MyApp få tillgång till alla användarens filer i Google Drive. Istället bör MyApp explicit påstå vad den vill ha tillgång till (t.ex. skrivskyddad åtkomst till filer i en specifik mapp). I OAuth 2.0-termer kallas detta en omfattning.
Du kan se termen "tillstånd" användas omväxlande med "omfattning" i sammanhanget med OAuth 2.0 eftersom ibland "omfattning" är tvetydig för icke-tekniska användare.
När användaren ger tillgång till MyApp utfärdar auktoriseringsservern en åtkomsttoken med den begärda omfattningen. Åtkomsttoken är sedan skickad till resursservern (Google Drive) för att få tillgång till användarens filer.
Naturligtvis kan vi ersätta Google Drive med våra egna API-tjänster. Till exempel, MyApp behöver få tillgång till OrderService för att hämta användarens orderhistorik. Denna gång, eftersom användarautentisering redan är gjord av identitetsleverantören och både MyApp och OrderService är under vår kontroll, kan vi hoppa över att be användaren att ge tillgång; MyApp kan direkt skicka begäran till OrderService med åtkomsttoken utfärdad av identitetsleverantören.
Åtkomsttoken kan innehålla en read:order omfattning för att indikera att användaren kan läsa sin orderhistorik.
Nu, låt oss säga att användaren av misstag anger en administrativ sidas URL i webbläsaren. Eftersom användaren inte är en administratör finns det ingen admin-omfattning i åtkomsttoken. OrderService kommer att avvisa begäran och returnera ett felmeddelande.
I det här fallet kan OrderService returnera en 403 Forbidden statuskod för att indikera att användaren inte är auktoriserad att få tillgång till den administrativa sidan.
För maskin-till-maskin (M2M) applikationer är ingen användare inblandad i processen. Applikationer kan direkt begära åtkomsttoken från identitetsleverantören och använda dem för att få tillgång till andra tjänster. Samma koncept gäller: åtkomsttoken innehåller de nödvändiga omfattningarna för att få tillgång till resurserna.
Vi kan se två viktiga saker att överväga när vi designar auktorisering för att skydda dina API-tjänster:
read:order, write:order) eller mer allmänna (t.ex. order) beroende på dina krav.admin omfattningen.När det gäller åtkomstkontroll är några populära tillvägagångssätt:
Det är värt att nämna att för båda tillvägagångssätten är det standardmässigt att verifiera åtkomstkontroll genom att kontrollera åtkomsttokenets omfattningar, istället för roller eller attribut. Roller och attribut kan vara mycket dynamiska och omfattningar är mer statiska vilket gör dem mycket enklare att hantera.
För detaljerad information om åtkomstkontroll kan du hänvisa till RBAC och ABAC: Åtkomstkontrollmodellerna du bör känna till.
Även om vi har nämnt termen "åtkomsttoken" många gånger har vi inte diskuterat hur man får en. I OAuth 2.0 utfärdas en åtkomsttoken av auktoriseringsservern (identitetsleverantören) efter ett lyckat auktoriseringsflöde.
Låt oss titta närmare på Google Drive-exemplet och anta att vi använder auktoriseringskodflödet:
Det finns några viktiga steg i flödet för utfärdande av åtkomsttoken:
Det ovanstående exemplet antar att auktoriseringsservern (identitetsleverantören) och resursservern är densamma (Google). Om de är separerade, tar vi exemplet med MyApp och OrderService, flödet kommer att se ut så här:
I detta flöde utfärdar auktoriseringsservern (IdP) både en ID-token och en åtkomsttoken till MyApp (steg 8). ID-token används för att identifiera användaren, och åtkomsttoken används för att få tillgång till andra tjänster som OrderService. Eftersom både MyApp och OrderService är förstapartstjänster brukar de inte be användaren om att ge tillgång; istället litar de på åtkomstkontrollen i identitetsleverantören för att avgöra om användaren kan få tillgång till resurserna (dvs. om åtkomsttoken innehåller de nödvändiga omfattningarna).
Slutligen, låt oss se hur åtkomsttoken används i maskin-till-maskin (M2M) applikationer. Eftersom ingen användare är inblandad i processen och applikationen är betrodd kan den direkt begära en åtkomsttoken från identitetsleverantören:
Åtkomstkontroll kan fortfarande tillämpas här. För OrderService spelar det ingen roll vem användaren är eller vilken applikation som begär datan; den bryr sig bara om åtkomsttokenet och de omfattningar det innehåller.
Åtkomsttoken är vanligtvis kodade som JSON Web Tokens (JWT). För att lära dig mer om JWT kan du hänvisa till Vad är JSON Web Token (JWT)?.
OAuth 2.0 introducerar konceptet omfattningar för åtkomstkontroll. Men du kan snabbt inse att omfattningar inte räcker:
openid, offline_access och profile. Det kan vara förvirrande att blanda dessa standardomfattningar med dina anpassade omfattningar.En vanlig lösning är att lägga till suffix (eller prefix) till omfattningsnamnen för att indikera resursen (API-tjänsten). Till exempel, read:order och read:product är tydligare än read och read. En OAuth 2.0-förlängning RFC 8707 introducerar en ny parameter resource för att indikera resursservern som klienten vill få tillgång till.
I verkligheten är API-tjänster vanligtvis definierade av URL:er, så det är mer naturligt att använda URL:er som resursindikatorer. Till exempel kan OrderService API representeras som:
Som du kan se, ger parametern bekvämligheten att använda de faktiska resurs-URL:erna i auktoriseringsförfrågningar och åtkomsttoken. Det är värt att nämna att RFC 8707 kanske inte implementeras av alla identitetsleverantörer. Du bör kontrollera dokumentationen för din identitetsleverantör för att se om den stöder resource-parametern (Logto stöder den).
I korthet kan resource-parametern användas i auktoriseringsförfrågningar och åtkomsttoken för att indikera resursen som klienten vill få tillgång till.
Det finns ingen begränsning på resursindikatorernas tillgänglighet, dvs. resursindikatorn behöver inte vara en verklig URL som pekar på en API-tjänst. Därför namnet "resursindikator" speglar väl dess roll i auktoriseringsprocessen. Du kan använda virtuella URL:er för att representera resurser du vill skydda. Till exempel kan du definiera en virtuell URL
https://api.example.com/admini din monolitiska applikation för att representera resursen som endast administratörer kan få tillgång till.
Vid det här laget har vi täckt grunderna för OAuth 2.0 och OpenID Connect, och hur man använder dem i olika applikationstyper och scenarier. Även om vi har diskuterat dem separat kan du kombinera dem enligt dina affärskrav. Den övergripande arkitekturen kan vara så enkel som detta:
Eller lite mer komplicerad:
När din applikation växer kommer du att se att identitetsleverantören (IdP) spelar en kritisk roll i arkitekturen; men det relaterar inte direkt till dina affärsmål. Medan det är en bra idé att lägga ut den på en pålitlig leverantör, behöver vi välja identitetsleverantören klokt. En bra identitetsleverantör kan avsevärt förenkla processen, minska utvecklingsinsatsen och spara dig från potentiella säkerhetsfallgropar.
För moderna molnapplikationer är identitetsleverantören (eller auktoriseringsservern) den centrala platsen för användar autentisering, identitetshantering, och åtkomstkontroll. Medan vi diskuterade många begrepp i detta inlägg finns det fortfarande många nyanser att överväga när man implementerar ett sådant system. Om du är intresserad av att lära dig mer kan du bläddra i vår blogg för mer djupgående artiklar.