refactor: 문서 개선 중
This commit is contained in:
+7
-7
@@ -28,7 +28,7 @@ Authorization Endpoint에서 리다이렉트, Token Endpoint, JWK(JSON Web Key)
|
||||
- **Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출**
|
||||
confidential client가 Token Endpoint를 부를 때 자기 자신을 인증한다.
|
||||
- **Public Client와 Confidential Client 구분 기준**
|
||||
클라이언트 종류가 정해져야 PKCE와 클라이언트 인증을 어디에 걸지 정해진다.
|
||||
현재 네 패턴에서 client type, callback/code-exchange ownership, PKCE와 client authentication이 어떻게 배치됐는지 함께 본다.
|
||||
|
||||
## 목적
|
||||
|
||||
@@ -36,24 +36,24 @@ Authorization Endpoint와 Token Endpoint는 하는 일도 다르고 요청이
|
||||
|
||||
하나는 브라우저가 페이지째 넘어가는 full-page navigation이고, 다른 하나는 서버가 보낼 수도 있고 브라우저가 직접 보낼 수도 있는 호출이다.
|
||||
|
||||
Authorization Endpoint 요청은 브라우저 주소창을 지나기 때문에 URL이 히스토리와 서버 로그, referrer에 남고, 이 요청에서는 클라이언트를 인증하지 않는다.
|
||||
Token Endpoint 요청은 값을 요청 본문과 Authorization 헤더에 싣고, 보내는 쪽은 클라이언트 종류에 따라 서버이거나 브라우저이며, 클라이언트 인증을 여기서 한다.
|
||||
Authorization Endpoint 요청 URL은 브라우저 주소창과 히스토리, Authorization Server의 접근 로그에 남을 수 있다. 다른 문서나 origin으로 이동할 때 referrer에 어느 범위까지 전달되는지는 브라우저의 Referrer-Policy와 이동 대상의 관계에 따라 달라진다. 이 요청에서는 client authentication을 수행하지 않는다.
|
||||
Token Endpoint 요청은 값을 요청 본문과 Authorization 헤더에 싣는다. 이 프로젝트에서는 AP1 public SPA가 브라우저에서 이 endpoint를 호출하고 AP2~AP4의 server-side component가 code를 교환한다. 이 호출 위치는 public/confidential client type 자체가 강제하는 것이 아니라 callback과 code exchange를 어느 구성요소가 소유하는지, 그리고 배포 구조를 어떻게 잡았는지에 따라 정해진다.
|
||||
|
||||
## 규칙
|
||||
|
||||
### 1. Authorization Endpoint에는 client_secret을 보내지 않는다
|
||||
|
||||
이 요청은 브라우저 주소창을 통해 나가기 때문에 URL이 주소창과 브라우저 히스토리, 서버 접근 로그에 남고, 링크를 타고 온 경우에는 referrer에도 남는다. 여기 실리는 값은 client_id, redirect_uri, response_type, scope, state, code_challenge, code_challenge_method다. 클라이언트 시크릿이 필요한 인증은 아직 하지 않는다.
|
||||
이 요청은 브라우저 주소창을 통해 나가기 때문에 URL이 주소창과 브라우저 히스토리, Authorization Server 접근 로그에 남을 수 있다. 이후 다른 문서로 이동할 때 referrer에 query까지 전달되는지는 Referrer-Policy와 same-origin/cross-origin 조건에 따라 달라진다. 여기 실리는 값은 client_id, redirect_uri, response_type, scope, state, code_challenge, code_challenge_method다. client authentication용 credential은 이 요청에 싣지 않는다.
|
||||
|
||||
이 목록에 없는 값을 여기에 실으면 그 값도 같은 곳에 함께 남는다.
|
||||
|
||||
### 2. Token Endpoint에서 비로소 클라이언트를 인증한다
|
||||
### 2. confidential client는 Token Endpoint에서 자신을 인증한다
|
||||
|
||||
code를 액세스 토큰으로 바꾸는 요청은 자격 증명을 URL 쿼리 문자열이 아니라 요청 본문과 Authorization 헤더에 싣기 때문에, 클라이언트 인증도 이 요청에서 한다. confidential client는 client_secret_basic처럼 클라이언트 시크릿을 함께 보낸다.
|
||||
code를 액세스 토큰으로 바꾸는 요청은 자격 증명을 URL 쿼리 문자열이 아니라 요청 본문과 Authorization 헤더에 싣기 때문에, client authentication도 이 요청에서 수행할 수 있다. 이 프로젝트의 confidential client들은 `client_secret_basic`을 사용하므로 server-side component가 client secret으로 자신을 인증한다.
|
||||
|
||||
주소창과 히스토리에 남지 않는다는 뜻이지 어디에도 기록되지 않는다는 뜻은 아니다. 애플리케이션 디버그 로그, 리버스 프록시 로그, 추적 도구와 APM(성능 모니터링 도구), 패킷 캡처에 남을 수 있어서 자격 증명을 가리는 마스킹을 따로 둔다.
|
||||
|
||||
이 요청을 누가 보내는지는 클라이언트 종류에 따라 갈린다. 서버가 보내면 서버끼리 주고받는 호출이고, 클라이언트 시크릿이 없는 SPA가 보내면 브라우저가 직접 보낸다. Token Endpoint를 서버 안에서만 부르게 하려면 클라이언트 종류부터 confidential client로 정해야 한다.
|
||||
이 프로젝트에서는 AP1 public SPA가 브라우저에서 token endpoint를 호출하고, AP2~AP4의 confidential component가 server-side에서 code를 교환한다. 다만 public/confidential client 구분 자체가 token endpoint의 호출 위치를 강제하는 것은 아니다. 서버 전용 교환은 callback과 code exchange를 server component가 소유하고 client credential이 browser로 노출되지 않도록 설계함으로써 만든다.
|
||||
|
||||
### 3. PKCE는 두 요청을 같은 주체에 묶는다
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ BFF(Backend For Frontend)는 화면에 필요한 API를 브라우저 대신 호
|
||||
|
||||
BFF 구조에서는 BFF가 authorization code를 토큰으로 교환하고 그 액세스 토큰으로 Resource Server를 호출한다. 브라우저의 로그인 상태는 세션이 담고 OAuth 토큰은 인가된 클라이언트(authorized client)가 보관하므로, 이 둘을 함께 관리해야 한다. 브라우저 응답에서 토큰이 보이지 않는다고 토큰을 다루는 일까지 없어지지는 않는다. BFF는 요청을 넘겨 주는 프록시가 아니라 로그인 상태와 토큰을 가진 보안 구성요소가 된다.
|
||||
|
||||
쿠키가 자격 증명이 되면 브라우저가 요청마다 자동으로 붙여 보내기 때문에, 값을 바꾸는 요청은 사용자가 의도한 것인지 따로 확인해야 한다. 서버를 재시작하거나 요청이 다른 레플리카로 가더라도 로그인 상태를 이어 갈 저장소도 함께 필요하다.
|
||||
쿠키가 자격 증명이 되면 브라우저가 요청마다 자동으로 붙여 보내기 때문에, 값을 바꾸는 요청에는 cookie만으로 만든 cross-site forged request를 구분할 CSRF 검증이 필요하다. 서버를 재시작하거나 요청이 다른 레플리카로 가더라도 로그인 상태를 이어 갈 저장소도 함께 필요하다.
|
||||
|
||||
쿠키로 인증하는 요청을 지킬 CSRF 검증, OAuth 토큰을 보관할 인가된 클라이언트 저장소, 로그아웃할 때 세션과 토큰을 함께 지우는 방법을 같이 설계해야 한다. BFF가 호출한 Resource Server에서 오류가 났을 때 이를 브라우저에 무엇으로 바꿔 돌려줄지도 함께 정해야 한다.
|
||||
|
||||
@@ -51,7 +51,7 @@ BFF는 이 세션을 확인한 뒤, 보관해 둔 액세스 토큰으로 Authori
|
||||
|
||||
### 2. 쿠키가 자격 증명이면 상태 변경 요청에 CSRF 검증을 둔다
|
||||
|
||||
BFF 구조에서는 브라우저가 요청할 때 세션 쿠키를 자동으로 보내기 때문에, 데이터를 만들고 고치고 지우는 것처럼 서버의 상태를 바꾸는 요청에는 그 요청이 실제 사용자의 의도에서 나왔는지 확인하는 CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 검증이 필요하다.
|
||||
BFF 구조에서는 브라우저가 요청할 때 세션 쿠키를 자동으로 보내기 때문에, 데이터를 만들고 고치고 지우는 것처럼 서버의 상태를 바꾸는 요청에는 예상한 anti-CSRF token이 함께 왔는지 검사해 cross-site forged request를 구분하는 CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 검증이 필요하다.
|
||||
|
||||
현재 구성에서는 서버가 CSRF 토큰을 쿠키로 내려보내고, JavaScript가 그 값을 읽어 요청 헤더에 다시 담아 보낸다. 서버는 쿠키와 헤더를 함께 확인해 요청을 검증한다.
|
||||
|
||||
|
||||
+7
-7
@@ -31,9 +31,9 @@ Google 로그인을 붙였다고 해서 SPA, Mediator, BFF, OAuth2-Proxy에 이
|
||||
|
||||
## 목적
|
||||
|
||||
외부 IdP(Identity Provider)는 Keycloak 앞에 서서 사용자 인증을 실제로 수행하는 인증 공급자이고, Google이 그중 하나다. 사용자가 Keycloak 로그인 화면에서 Google을 고르면 브라우저는 Google로 이동해 인증을 마치고, Keycloak이 그 결과를 확인해 자신이 가진 사용자 정보와 연결한다. 그런 다음 Keycloak이 애플리케이션에 자신이 발급한 Authorization Code를 전달한다.
|
||||
외부 IdP(Identity Provider)는 Keycloak 앞에서 사용자 인증을 수행한다. Google이 그중 하나다. 사용자가 Keycloak 로그인 화면에서 Google을 고르면 브라우저는 Google에서 인증을 마친다. Keycloak은 그 결과를 검증해 realm 사용자와 연결한 뒤 자신이 발급한 Authorization Code를 애플리케이션에 전달한다.
|
||||
|
||||
그래서 Google 같은 외부 IdP를 추가해도 애플리케이션의 인증 구조는 달라지지 않는다. 토큰을 브라우저가 직접 받을지 서버에서 관리할지, 브라우저와 서버 중 어느 계층이 Resource Server의 API를 호출할지는 기존 SPA, Mediator, BFF, OAuth2-Proxy 구조 중 무엇을 골랐는지가 정한다.
|
||||
Google 같은 외부 IdP가 추가돼도 애플리케이션이 상대하는 OAuth 경계는 Keycloak이다. 토큰을 브라우저가 받을지 서버가 관리할지와 Resource Server를 누가 호출할지는 기존 SPA, Mediator, BFF, OAuth2-Proxy 구조가 정한다.
|
||||
|
||||
## 규칙
|
||||
|
||||
@@ -43,7 +43,7 @@ Google 로그인을 붙였다고 해서 SPA, Mediator, BFF, OAuth2-Proxy에 이
|
||||
|
||||
Google에서 인증이 끝나면 그 결과는 먼저 Keycloak이 검증한다. 이후 애플리케이션이 쓰는 Authorization Code와 토큰은 Google이 아니라 Keycloak이 발급한 것이고, Resource Server가 검증하는 토큰도 Keycloak이 발급한 것이다.
|
||||
|
||||
로그인 화면에서 Google이나 다른 IdP를 고르게 하거나, IdP마다 다른 계정을 Keycloak 사용자와 어떻게 연결할지를 따로 처리하는 것은 자연스럽다. 다만 Resource Server가 Google이 발급한 토큰과 Keycloak이 발급한 토큰을 각각 다르게 검증하거나, 애플리케이션의 인가 로직이 로그인에 쓴 IdP에 따라 갈리기 시작한다면 외부 IdP와 애플리케이션을 갈라놓던 Keycloak의 역할이 제대로 지켜지고 있는지 확인할 필요가 있다.
|
||||
로그인 화면에서 IdP를 고르는 일과 외부 계정을 Keycloak 사용자에 연결하는 일은 broker 경계 안에 있다. Resource Server가 Google token과 Keycloak token을 따로 검증하거나 애플리케이션 인가가 로그인 IdP에 따라 갈리기 시작하면 이 경계가 애플리케이션까지 확장된 것이다.
|
||||
|
||||
### 2. 외부 계정은 IdP와 subject 조합으로 식별한다
|
||||
|
||||
@@ -55,15 +55,15 @@ Google에서 인증이 끝나면 그 결과는 먼저 Keycloak이 검증한다.
|
||||
|
||||
### 3. 이메일 충돌은 별도의 계정 연결 문제로 다룬다
|
||||
|
||||
외부 IdP가 전달한 이메일 주소가 기존 계정의 이메일과 같더라도, 이메일이 같다는 사실만으로 두 계정이 같은 사용자의 것이라고 확신할 수 없기 때문에 자동으로 연결하지 않는다.
|
||||
외부 IdP가 전달한 이메일이 기존 계정과 같아도 자동으로 연결하지 않는다. 같은 이메일이라는 사실만으로 두 계정의 소유자가 같다고 확인할 수 없기 때문이다.
|
||||
|
||||
계정을 연결해야 한다면 기존 계정으로 다시 로그인하게 하거나 추가 인증을 요구하는 등, 사용자가 그 계정의 실제 소유자인지 확인하는 절차를 따로 거친다.
|
||||
계정 연결에는 기존 계정 재로그인이나 추가 인증처럼 기존 계정의 소유권을 확인하는 절차가 별도로 필요하다.
|
||||
|
||||
### 4. mock provider 테스트와 실제 IdP 검증을 구분한다
|
||||
|
||||
지금까지 mock provider로 확인한 것은 Keycloak이 외부 IdP의 인증 결과를 정상적으로 받아들이는지와, 필요한 사용자 정보가 올바르게 매핑되는지까지다.
|
||||
현재 확인 범위는 mock provider를 이용한 broker 동작과 claim mapping 계약까지다.
|
||||
|
||||
mock provider 테스트만으로는 실제 외부 IdP와의 연동까지 검증할 수 없다. 실제 계정으로 로그인하는 과정과 공개 HTTPS 콜백, 사용자 동의(Consent) 화면, 외부 IdP가 적용하는 도메인 정책 등은 아직 확인하지 않았다. 그래서 실제 외부 IdP를 연결해 전체 로그인 흐름을 따로 검증해야 한다.
|
||||
실제 계정 로그인, 공개 HTTPS callback, 사용자 동의(Consent), 외부 IdP의 도메인 정책은 확인하지 않았다. 따라서 mock provider 검증 결과를 실제 IdP 운영 연동의 완료 조건으로 쓰지 않는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
|
||||
+9
-9
@@ -41,7 +41,7 @@ SPA(Single Page Application), Mediator, BFF(Backend for Frontend), Forward-Auth
|
||||
|
||||
Forward-Auth 구조에서는 애플리케이션이 OAuth 토큰을 직접 관리하는 책임을 더 줄일 수 있다. 대신 애플리케이션이 엣지에서 넘어온 사용자 정보 헤더를 신뢰하게 되므로, 헤더 위조 방지와 직접 접근 차단, 신뢰할 수 있는 네트워크 경계를 구성해야 한다.
|
||||
|
||||
어느 구조가 더 안전한지를 먼저 정하지 않고, 요구사항마다 무엇을 확인해야 하는지를 본다.
|
||||
선택 기준은 어느 구조가 더 안전한지에 대한 단일 순위가 아니라, 요구사항마다 달라지는 자격 증명 위치와 운영 책임이다.
|
||||
|
||||
## 규칙
|
||||
|
||||
@@ -49,7 +49,7 @@ Forward-Auth 구조에서는 애플리케이션이 OAuth 토큰을 직접 관리
|
||||
|
||||
브라우저가 액세스 토큰을 쓰는지, Resource Server를 누가 호출하는지, 서버가 어떤 인증 상태를 관리하는지, Resource Server가 어떤 자격 증명을 검증하는지, CSRF를 어디에서 처리하는지를 확인한다.
|
||||
|
||||
이 다섯 항목은 패턴 이름 대신 요청 하나를 끝까지 따라가서 채운다. 실제 엔드포인트와 메서드, 중간에 생기는 데이터, 성공 응답과 실패 응답까지 봐야 한다. 같은 질문을 로그인할 때와 로그인 뒤 API를 부를 때 각각 던진다.
|
||||
비교 단위는 패턴 이름이 아니라 요청 한 번의 실제 경로다. 비교 입력에는 엔드포인트와 메서드, 중간에 생기는 자격 증명, 성공·실패 응답이 포함되고 로그인 구간과 로그인 뒤 API 호출 구간을 각각 나눠 본다.
|
||||
|
||||
SPA와 Mediator에서는 브라우저가 액세스 토큰으로 Resource Server를 직접 호출한다. SPA는 Bearer 액세스 토큰을 Authorization 헤더에 직접 넣고 인증에는 쿠키를 쓰지 않는다. Mediator는 로그인 세션과 OAuth 토큰을 서버에서도 관리하고, 로그인이 끝나면 브라우저에 액세스 토큰을 전달한다.
|
||||
|
||||
@@ -65,23 +65,23 @@ Forward-Auth에서는 인증 프록시가 세션을 관리하고, 인증이 끝
|
||||
|
||||
### 3. 선택 조건과 운영 책임을 같이 문서화한다
|
||||
|
||||
어떤 인증 구조를 골랐는지만 적지 않는다. 어떤 보안 요구사항과 운영 조건 때문에 그 구조를 골랐는지 함께 적는다.
|
||||
선택 기록에는 구조 이름과 함께 그 선택을 만든 보안 요구사항과 운영 조건이 들어간다.
|
||||
|
||||
그 구조를 적용하기 어려운 조건도 같이 적는다. 브라우저에 OAuth 토큰을 둘 수 없는 환경에서는 SPA를 고르기 어렵다. 애플리케이션으로 바로 들어오는 경로나 사용자 정보 헤더를 안전하게 통제할 수 없는 환경에서는 Forward-Auth를 적용하기 어렵다.
|
||||
적용이 어려운 조건도 선택 기준의 일부다. 브라우저에 OAuth 토큰을 둘 수 없는 환경에서는 SPA를 고르기 어렵고, 애플리케이션 직접 경로나 사용자 정보 헤더를 통제할 수 없는 환경에서는 Forward-Auth를 적용하기 어렵다.
|
||||
|
||||
### 4. 이름으로 운영 속성을 추정하지 않는다
|
||||
|
||||
실제 운영에 적용할 때는 서버가 재시작되거나 특정 인스턴스에 장애가 나도 로그인 상태를 유지할 수 있는지, 여러 레플리카가 필요한 세션과 토큰 정보를 공유할 수 있는지, 저장소 장애가 났을 때 어떻게 복구할지를 따로 확인해야 한다.
|
||||
운영 조건에는 서버 재시작이나 인스턴스 장애 뒤 로그인 유지 여부, 여러 레플리카의 세션·토큰 상태 공유 방식, 저장소 장애 복구 방식이 포함된다.
|
||||
|
||||
내부 자격 증명이나 암호화 키와 같은 비밀값을 안전하게 보관하고 교체할 수 있는지도 함께 검증한다. 구조를 고를 때 이런 운영 항목까지 같이 적는다.
|
||||
내부 자격 증명과 암호화 키 같은 비밀값의 보관·교체 방식도 같은 운영 조건에 속한다.
|
||||
|
||||
### 5. 자격 증명의 위치가 바뀌면 저장·전달·검증 주체도 바뀐다
|
||||
|
||||
패턴을 바꿀 때는 기존 책임이 어느 계층으로 옮겨 가는지까지 확인해야 한다.
|
||||
패턴이 바뀌면 저장·전달·검증 책임도 다른 계층으로 이동한다.
|
||||
|
||||
예를 들어 Forward-Auth 구조에서는 엣지가 인증된 사용자 정보를 헤더로 애플리케이션에 전달할 수 있다. 처음에는 사용자 이름이나 이메일처럼 인증에 필요한 정보만 전달하더라도, 애플리케이션의 요구사항이 늘면서 역할이나 권한, 도메인에 묶인 사용자 정보까지 헤더에 계속 붙을 수 있다.
|
||||
|
||||
엣지가 전달해야 하는 정보가 이렇게 늘어나고, 인가 판단이나 화면에 필요한 여러 API 응답의 조합까지 애플리케이션에 필요해진다면, 그 책임을 엣지에 계속 얹기보다 BFF에서 인가와 API 호출을 처리하는 구조가 더 맞는지 다시 검토한다.
|
||||
엣지가 전달할 정보가 역할·권한·도메인 정보까지 늘어나고 여러 API 응답의 조합과 인가 판단도 필요해지면, BFF가 인가와 API 호출을 소유하는 구성이 비교 대상이 된다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
@@ -91,7 +91,7 @@ Forward-Auth에서는 인증 프록시가 세션을 관리하고, 인증이 끝
|
||||
|
||||
## 예외
|
||||
|
||||
- 브라우저에 토큰을 둘 수 없고 서버가 API를 조합해야 하면 남는 선택지는 하나다.
|
||||
- 이 문서에서 비교하는 AP1~AP4 네 패턴만 놓고 보면, 브라우저에 OAuth token을 둘 수 없고 server-side API composition이 필요할 때 AP3 BFF가 해당 조건을 만족한다.
|
||||
- 학습이나 시연이 목적이면 운영 속성까지 비교하지 않아도 된다.
|
||||
|
||||
## 예시
|
||||
|
||||
+12
-23
@@ -20,9 +20,8 @@ source:
|
||||
|
||||
# Public Client와 Confidential Client 구분 기준
|
||||
|
||||
OAuth 클라이언트의 종류는 클라이언트 시크릿을 안전하게 보관할 수 있는지로 정한다.
|
||||
SPA(Single Page Application)는 브라우저에서 실행되기 때문에 시크릿을 사용자에게 노출하지 않고 보관할 방법이 없다.
|
||||
그래서 SPA는 대개 public client로 등록한다.
|
||||
OAuth 클라이언트 종류는 인증 서버에 대해 장기 자격 증명의 기밀성을 유지하고 신뢰할 수 있는 클라이언트 인증을 수행할 수 있는지로 구분한다.
|
||||
AP1의 SPA(Single Page Application)는 브라우저 실행 환경에서 이 조건을 충족하기 어려워 public client로 두었다. AP2~AP4는 서버 구성요소가 자격 증명을 보호할 수 있어 confidential client로 구성했고, 이 프로젝트에서는 `client_secret_basic`을 사용한다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -31,29 +30,23 @@ SPA(Single Page Application)는 브라우저에서 실행되기 때문에 시크
|
||||
- **Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출**
|
||||
confidential client로 등록해도 액세스 토큰을 브라우저까지 보낼지는 따로 정한다.
|
||||
- **Authorization Code Flow의 Endpoint와 Credential 이동 기준**
|
||||
클라이언트 종류에 따라 token endpoint에서 하는 클라이언트 인증이 달라진다.
|
||||
public client와 confidential client는 토큰 엔드포인트에서 사용하는 클라이언트 인증 방식이 다르다.
|
||||
|
||||
## 목적
|
||||
|
||||
OAuth 클라이언트를 등록하려면 이 클라이언트를 public client로 볼지 confidential client로 볼지부터 정해야 한다.
|
||||
그래야 authorization code를 토큰으로 교환할 때 PKCE(Proof Key for Code Exchange)를 쓸지, 클라이언트 시크릿으로 클라이언트를 인증할지 정할 수 있다.
|
||||
클라이언트 종류가 정하는 범위는 자격 증명 보호와 클라이언트 인증이다. PKCE(Proof Key for Code Exchange)는 authorization code를 교환하는 쪽이 원래 verifier를 가진 주체인지 확인하는 별도 보호 장치라서 클라이언트 인증과 함께 사용할 수 있다.
|
||||
|
||||
클라이언트 종류를 나누는 기준은 클라이언트 시크릿을 사용자에게 노출하지 않고 안전하게 보관할 수 있는지다.
|
||||
SPA는 브라우저에서 실행되기 때문에 코드에 시크릿을 넣어도 개발자 도구 같은 것으로 사용자가 확인할 수 있고, 그래서 시크릿을 안전하게 보관할 수 없는 public client로 구성한다.
|
||||
AP1 SPA는 public client이고 브라우저가 code를 직접 교환한다. AP2~AP4는 서버 구성요소가 confidential client로 code를 교환하며 이 프로젝트에서는 `client_secret_basic`을 사용한다.
|
||||
|
||||
서버나 BFF(Backend for Frontend)는 시크릿을 서버 안에만 두고 브라우저에 전달하지 않을 수 있으므로 confidential client로 구성할 수 있다.
|
||||
|
||||
클라이언트 종류가 토큰을 누가 보관하는지까지 정해 주지는 않는다.
|
||||
클라이언트 종류는 시크릿을 안전하게 보관할 수 있는지로 정하고, 토큰을 브라우저와 서버 중 어디에서 관리할지는 애플리케이션의 인증 구조에 따라 따로 정한다.
|
||||
토큰 보관 위치와 API 호출 주체는 클라이언트 종류와 다른 축이다. 같은 confidential client라도 AP2는 액세스 토큰을 브라우저에 돌려주고, AP3 BFF(Backend for Frontend)와 AP4 프록시는 서버 쪽에서 다음 요청을 만든다.
|
||||
|
||||
## 규칙
|
||||
|
||||
### 1. 클라이언트 시크릿을 숨길 수 있는지로 종류를 정한다
|
||||
### 1. 실행 환경에서 장기 자격 증명을 보호할 수 있는지 구분한다
|
||||
|
||||
애플리케이션의 배포 파일이나 실행 중인 메모리에서 사용자가 클라이언트 시크릿을 확인할 수 있다면 그 시크릿은 안전하게 보관할 수 없으므로 public client로 본다.
|
||||
시크릿을 서버 안에만 보관하고 사용자에게 전달되지 않도록 통제할 수 있다면 confidential client로 구성할 수 있다.
|
||||
브라우저 SPA나 사용자 기기에 설치되는 네이티브 앱처럼 배포물을 사용자가 직접 가진 환경에서는 애플리케이션 안에 넣은 장기 자격 증명을 비밀로 유지하기 어렵다. 이런 클라이언트는 public client로 다룬다.
|
||||
|
||||
네이티브 앱은 브라우저에서 실행되지는 않지만 애플리케이션이 사용자 기기에 설치되기 때문에, 배포 파일을 분석하면 안에 들어 있는 클라이언트 시크릿을 확인할 수 있다. 그래서 네이티브 앱도 대개 public client로 다룬다.
|
||||
서버 구성요소는 자격 증명을 사용자에게 배포하지 않고 인증 서버에 자신을 인증할 수 있다. 이 프로젝트는 공유 시크릿과 `client_secret_basic`을 사용한다. Confidential client의 인증 수단은 공유 시크릿 하나로 제한되지 않으며 private key나 mTLS 같은 방식도 가능하다.
|
||||
|
||||
### 2. public client에서 Authorization Code Flow에 PKCE를 함께 쓴다
|
||||
|
||||
@@ -68,7 +61,7 @@ Authorization Server는 처음 받은 code_challenge와 맞춰 보고 같은 요
|
||||
### 3. confidential client에도 PKCE를 함께 쓸 수 있다
|
||||
|
||||
클라이언트 인증과 PKCE는 보호하는 대상이 다르기 때문에 confidential client에서 둘을 같이 쓸 수 있다.
|
||||
클라이언트 인증은 token endpoint에 요청을 보낸 쪽이 그 클라이언트가 맞는지 확인하고, PKCE는 authorization code를 받은 쪽이 로그인을 시작할 때 만든 code_verifier를 가지고 있는지 확인한다.
|
||||
클라이언트 인증은 토큰 엔드포인트에 요청을 보낸 쪽이 등록된 클라이언트인지 확인한다. PKCE는 authorization code를 받은 쪽이 로그인을 시작할 때 만든 `code_verifier`를 가지고 있는지 확인한다.
|
||||
|
||||
### 4. public client에서는 implicit flow와 direct access grant를 끈다
|
||||
|
||||
@@ -81,13 +74,9 @@ direct access grant는 애플리케이션이 사용자의 아이디와 비밀번
|
||||
|
||||
### 5. 클라이언트 종류만으로 브라우저가 토큰을 받는지가 정해지지는 않는다
|
||||
|
||||
confidential client가 authorization code를 토큰으로 교환하더라도, 그렇게 받은 액세스 토큰을 다시 브라우저에 전달하는 구조를 만들 수 있다.
|
||||
confidential client가 authorization code를 교환해도 액세스 토큰을 브라우저에 다시 전달할 수 있다. AP2 mediator는 브라우저가 Resource Server를 직접 호출하기 때문에 액세스 토큰을 응답으로 내보낸다.
|
||||
|
||||
클라이언트 종류는 클라이언트 시크릿을 어디에 안전하게 보관할 수 있는지를 말한다.
|
||||
액세스 토큰이 브라우저까지 가는지는 어느 계층이 실제 API 호출을 맡도록 설계했는지에 따라 따로 정해진다.
|
||||
|
||||
이 기준으로 등록한 클라이언트 넷 중 셋이 confidential인데, 그 셋에서 액세스 토큰이 브라우저까지 가는지는 갈렸다.
|
||||
mediator 구성에서는 브라우저가 API를 직접 불러서 액세스 토큰이 응답으로 내려갔고, BFF와 프록시 구성에서는 서버 쪽이 API를 불러서 브라우저에 줄 것이 없었다.
|
||||
AP3 BFF와 AP4 프록시는 다음 API 요청을 서버 쪽에서 만들기 때문에 브라우저에 액세스 토큰을 줄 필요가 없다. 세 구조가 모두 confidential client라는 사실만으로 이 차이는 설명되지 않는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
|
||||
+1
-1
@@ -107,5 +107,5 @@ Mediator나 BFF처럼 서버가 애플리케이션 세션과 Authorized Client
|
||||
- 리프레시 토큰 : 새 액세스 토큰을 받는 장기 자격 증명이다
|
||||
- 애플리케이션 세션 쿠키 : 서버에 있는 로그인 상태를 찾는 자격 증명이다
|
||||
- 프록시 세션 쿠키 : 프록시의 인증 엔드포인트에 제시하는 최소 상태다
|
||||
- CSRF 토큰 : 쿠키가 자동으로 붙는 상태 변경 요청의 의도를 확인한다
|
||||
- CSRF 토큰 : 쿠키가 자동으로 붙는 상태 변경 요청에 별도 검증 값을 요구해 cross-site forged request를 구분한다
|
||||
- 사용자 정보 헤더 : 엣지가 확인한 사용자 정보이고 JWT 토큰이 아니다
|
||||
|
||||
Reference in New Issue
Block a user