Authentication
Authentication이란 누군가의 신원을 인증해주는 절차이다. 웹 사이트에서 보통 username과 password를 이용하여 로그인 하는데 이런 로그인 뿐만 아니라 HTTPS를 이용한 접근에 Browser가 TLS를 이용해 Server에 인증하고 가짜 웹사이트를 로딩하는지, 혹은 서버간 통신에서 request 요청에 대해 악의적인 사용을 피하기 위해 인증하는 등에 사용한다.
HTTP는 stateless하기에 통신의 상태가 저장되지 않아 아래 현재는 대중적인 방법인 basic auth, session, token, jwt와 같은 방법으로 저장한다.
1. 요소
Authentication는
- Username / Password - [지식 요소]
- Security Codes (PIN) - [지식 요소]
- Hard Tokens (Hardware) / Soft Tokens (OTP) - [소유 요소]
- 생체 인증(지문, 음성 인식, 얼굴 인식 등) - [고유 요소]
- 지리적 위치 및 주소 [위치 기반]
과 같은 요소들이 있다.
과거 전통적인 방법으로 비밀번호만 갖고는 아무리 복잡하게 설정하고 자주 변경하더라도 보안에 충분하지 않습니다. 이런 요소들을 통해 Username, Password를 통해 로그인 하고 OTP를 통해 인증 받는 등 여러가지 요소를 합쳐 인증 받는 MFA(Multi Factor Authentication, 다단계 인증 솔루션 - 더 민감한 경우 권장)과 반드시 두가지를 혼합해서 인증해야하는 2FA(2 Factor Authentication, 이중 인증 솔루션)의 방법으로 인증 솔루션이 등장했습니다.
Authentication 하여 인증을 확인(실패: HTTP 401)하고, Authorization 으로 권한을 확인하는(실패: HTTP: 403) 절차를 통해 인증 전략에 대해 소개하겠습니다.
2. Basic Auth
웹 표준 RFC 7167으로 정의되어 모든 브라우저들이 지원한다. Basic Authentication은 다음과 같은 절차를 따른다.
단계 1. 브라우저가 URL에 접근한다. Request가 서버에 전송되어 Authorization header가 유효한지 확인한다.
처음 요청이라 header가 없으므로 401 Unauthorized 와 함께 WWW-Authenticate: Basic realem="___" 을 브라우저에 전송한다.
단계 2. 브라우저가 WWW-Authenticate 헤더가 담긴 response를 보고 유저에게 로그인 팝업을 전송한다. 유저가 username과 password를 입력하고 전송하면 헤더에 Authorization: Basic base64("username:password")를 포함하여 같이 전송한다.
단계3: 서버가 헤더를 디코딩하고 username과 password를 확인한다. 만약 유효한 credential이라면 success response를 브라우저에 전송해준다.
이러한 과정에서 브라우저와 서버간 credential 정보가 텍스트로 교환되기 때문에 보안상 이유로 HTTPS 를 반드시 사용해야한다.
3. Session Based
세션은 다음과 같은 절차로 인증을 처리한다.
단계 1. 브라우저에서 username과 password를 로그인 POST method와 함께 서버에 전송한다.
단계 2. 서버에서 session을 생성하고 해당 유저가 또 다른 요청을 할 때 누구인지 추적하기 위해 유저 정보를 session에 저장한다. 해당 정보는 redis, 파일 시스템, database와 같은 곳에 저장되고 예를 들어 redis에 {id: ..., email: ...} 과 같은 형식으로 저장되었다면 서버는 생성된 session id를 브라우저에 전송합니다.
단계 3. 브라우저는 받은 session id를 쿠키(기본값, 일반적), 로컬 스토리지, 세션 스토리지에 저장합니다.
단계 4. 브라우저가 authorization이 필요한 요청을 할 때 쿠키에 저장된 session id를 서버에 전송하고 redis에서 정보를 비교합니다.
일반적으로 세션은 정보를 database에 저장하는 방식으로 로그인 된 유저 정보를 확인하여 고객을 탈퇴시키거나, 로그인된 디바이스를 확인하고 기기에서 로그아웃하기와 같은 기능, 공유 계정 갯수 제한과 같은 기능들을 필요로 할 때 사용한다. 브라우저에서 session id만 저장하고 다른 정보들은 database에서 확인할 수 있어 용량 제한이 있는 cookie를 사용하여 유효기간과 httpsOnly, Secure 등의 옵션을 주어 비교적 JWT보다 안전하다.
반면유저가 늘어날 수록 database가 커져야하고 분산환경에서는 유저가 인증하였더라도 다른 서버로 인식하여 sticky session, session clustering 과 같은 방법을 통해 로드밸런서의 관리가 추가적으로 필요하다.
4. Token Based
토큰기반 인증은 사용자가 자신의 신원을 확인하고 그 대가로 고유한 액세스 토큰을 발급 받을 수 있는 프로토콜이다. 한번 인증하여 토큰의 수명기간 동안 동일한 웹 페이지, 앱 또는 동일한 토큰으로 보호되는 리소스로 돌아갈 때마다 인증 없이 토큰이 발급된 웹 또는 앱에 접근할 수 있습니다. 많은 사용자들이 휴대폰(앱)을 통해 시스템에 액세스할 때, cookie를 사용할 수 없기에 token을 사용하는데
USB장치와 같은 물리적인 항목을 시스템에 연결하는 연결식, 가까운 거리에서 자동으로 인증하는 비접촉식, 휴대폰 2FA 인증과 같은 비연결식과 같은 방식으로 추가 인증할 수 있고,
토큰을 이용한 인증은 다음과 같이 진행됩니다.
단계 1. 사용자가 서버 또는 리소스에 로그인과 같은 Authentication 과 함께 액세스를 요청합니다.
단계 2. 서버는 사용자 비밀번호, 사용자 권한 등을 확인합니다.
단계 3. 서버는 (링, 키, OTP 등 인증 장치와 통신하여) 확인 후 토큰을 발행하여 사용자에게 전달합니다.
단계 4. 토큰은 작업이 진행되는 동안 로그아웃 등으로 토큰이 폐기되거나, 지정된 기간이 끝나지 않는 한 브라우저 내에 있어 통신을 인증해줍니다.
이러한 인증 방식은 Session과 다르게 리소스 서버에 공간을 차지하지도 않고 토큰을 훔치기에도 훨씬 어려운 방법이라 보안에도 더 안정적입니다.
5. JWT
많은 사용자들이 휴대폰(앱)을 통해 시스템에 액세스할 때, cookie를 사용할 수 없기에 token을 사용하는데 RFC 7591로 웹 표준에 정의된 JWT (JSON Web Token)을 가장 보편적으로 많이 사용한다.
JWT는 헤더(토큰 유형, 서명 알고리즘), 페이로드(registered claims: 토큰 발급자, 만료, public claims: 정보 전달을 위한, private claims: 해당 유저의 특정 정보), 서명으로 이루어져 있는데 JSON 형태로 이루어진 토큰의 header와 payload를 base64로 encode해서 dot(.)으로 연결시키고 signature 부분에는 private key와 선택한 알고리즘으로 header와 payload를 한번 더 암호하여 합친 값으로 구성되며, 이로서 URL safe한 토큰이 됩니다.
서버에 이 JWT가 전송되면 선택한 알고리즘의 공개키로 signautre를 열어봐서 넘어온 header, payload와 일치하는지 확인하는 방식으로 signing, verification을 할 수 있습니다.
JWT는 다음과 같은 방식으로 인증된다. 아래는 Access Token으로만 관리하게 되면 탈취당할 경우 보안에 취약하여 Refresh Token과 함께 사용하는 방법이 많기에 접근용 Access Token과 재발급용 Refresh Token과 함께 이야기하겠습니다.
단계 1. 클라이언트가 username, password를 포함한 로그인을 서버에 요청한다.
단계 2. 서버는 인증 요청을 받으면 JWT를 생성하고 이를 Cookie에 담아 클라이언트에게 발급한다. JWT를 생성할 때 Access Token(일반적으로 유효기간 1시간), Refresh Token(일반적으로 유효기간 2주)을 같이 생성하고 클라이언트에 발급한다. Refresh Token은 추가적인 인증과 차단 기능 등을 위해 DB에도 저장해둔다.
단계 3. 클라이언트는 서버로부터 받은 JWT를 Local Storage에 저장하고 서버에 API 요청을 보낼 때 헤더에 Authorization에 Access Token을 포함시켜 보낸다. 만약 Access Token이 만료되었다면 Refresh Token을 이용해서 Access Token을 갱신한다. (AccessToken은 유효하지만 Refresh Token은 만료 되었으면 Access Token을 검증하여 Refresh Token을 재발급하고 둘다 만료된 경우엔 다시 로그인을 요청하여 새로 발급 받는다.)
Refresh Token은 1번이라도 사용했으면 Access Token을 재발급할 때 다시 재발급하여 해킹의 위험도를 낮춘다.
단계 4. 서버는 클라이언트가 보낸 JWT를 verification을 통해 확인하고 인증이 통과된다면 유저의 정보들을 클라이언트에 전달해준다.
앱이나 웹앱 환경 뿐만 아니라 데이터베이스를 사용하지 않아 인증서버로 경유할 필요가 없어 MSA에서 복잡도를 굉장히 낮출 수 있고 session에서 언급한 sticky session, session clustering와 같은 문제도 발생하지 않는다.반면 쿠키에 저장되는 session id 보다 사이즈가 크고 서버에서 제어가 불가능하기에 관리할수 없다는 단점도 존재한다.
6. OAuth
Open Authorization의 약자로 인터넷 사용자들이 비밀번호 없이 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트/어플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로 접근 위임을 위한 개방형 표준이다. 과거 표준방식이 없을 때 각 회사가 자신만의 방법으로 사용자를 확인하였지만 이러한 방식을 표준화하는 방식으로, 이 인증을 공유하는 애플리케이션끼리는 별도의 인증이 필요없다. 그리고 서비스 프로바이더에
OAuth는 다음과 같은 방식으로 인증한다.
단계 1. Consumer가 Service Provider에게 Request Token을 요청한다.
단계 2. Service Provider가 Request Token을 발급해준다.
단계 3. 어플리케이션이 사용자(User)를 서비스 제공자로 이동시키며 해당 회사에 인증을 시키고 어플리케이션으로 Redirect 시켜준다.
단계 4. Consumer가 Service Provider에 Access Token을 요청한다.
단계 5. Service Provider가 Access Token을 발행한다.
단계 6. Consumer가 Access Token을 이용하여 User에 접근한다.
토큰 강제 만료, 확장성 등을 위해 OAuth2가 등장했는데, 기존에 user, consumer, service provider, consumer secret, request token, access token으로 복잡한 구성에서 resource owner, client, resource server(api), authorization server로 간단한 구성을 갖추게 되었다.
Auth2.0은 Authorization Code Grant, Implicit Grant, Password Credentials Grant, Client Credential Grant등의 방법으로 인증할 수 있는데 가장 대중적으로 사용하는 Authorization Code Grant와 Implicit Grant를 보자.
Authorization Code Grant는 Confidential Client를 상대로 사용하는 방법인데 Access Token 권한 서버가 클라이언트와 리소스 서버간 중재역할을 하는 서버사이드 방식이고 로그인 페이지 URL에 response_type=code 라고 넘긴다.
Public Client를 상대로 Implicit Grant를 사용하는데 OAuth의 방식과 유사해 가장 많이 사용되고 브라우저 기반, 모바일 기반 어플리케이션에서 이 방식을 사용한다. Authorization Code Grant에서 인증 코드 교환 과정이 없이 Access Token이 바로 URL에 발급되서 보안에 취약하여 Read-Only 서비스에서 이용한다. 로그인 페이지 URL에 response_type=token 으로 넘긴다.
아래는 Authorization Code Grant 방식의 인증 과정이다.
단계 1. Resource Owner가 Client에 서비스 접근 및 로그인 요청을 한다.
단계 2. Client가 Authorization Server에 로그인을 요청한다.
단계 3. Authorization서버는 Resource Owner에게 로그인 페이지를 제공하고 Username, Password를 요청한다.
단계 4. Resource Owner는 제공된 로그인 페이지에 Username과 Password를 입력하고 전송한다.
단계 5. Authorization 서버가 Authorization Code를 Resource Owner에게 발급해준다.
단계 6. Resource Owner가 Authorization Code를 발급 받으면 Callback URL로 이동시켜 Client로 보낸다.
단계 7. Client가 Authorization Server에 Access Token을 요청하고 발급 받는다. 이 때 Access Token을 Client에 저장한다.
단계 8. Client는 인증 완료 및 로그인 성공을 Resource Owner에게 제공한다.
단계 9. 이후 Resource Owner가 Client에 서비스를 요청하면 Client는 Resource Server에 Access Token을 포함하여 API를 요청한다.
단계 10. Resource 서버는 Access Token을 검증하고 Client에 서비스를 제공한다.
단계 11. Client는 제공된 서비스를 Resource Owner에게 제공한다.
7. SSO
SSO(Single Sign On)은 1회의 사용자 인증으로 다수의 애플리케이션 및 웹사이트에 사용자 로그인을 허용하는 인증 솔루션입니다. 한 플랫폼 내에서 다수의 어플리케이션에 계속해서 로그인 하는 번거로움을 줄이고자 auth URL에 리다이렉트 시켜 한 번의 로그인으로 인증이 성공하면 콜백 URL로 다시 리다이렉트 시켜 Client에 세션 쿠키를 생성해줘 사용자 편의성을 높일 수 있는 전략입니다.
SSO 전략으로는 OIDC, SAML이 사용되는데
2001년에 SAML이 나왔는데 웹사이트에서는 SSO 전략으로 괜찮지만 서버 없이 브라우저 환경에서만 Service Provider와 Identity Provider가 인증정보를 주고 받는 방식이라 인증 요청을 하고 Identity Provider가 XHTML 형태로 응답을 주면 클라이언트가 HTML POST 방식으로 만들어 인증 정보를 Service Provider에게 전달해야해서 모바일에서 별도의 웹을 띄워서 인증을 받는다면 UX가 떨어질 수 있기 때문에 2005년 인가 목적의 제네릭한 OAuth2.0 이 나오고 2006년에 OAuth2.0 기반의 인증 목적의 OpenID Connect 방식이 나타났다.
OpenID Connect에는 OAuth2.0 인가 방식과 동일한 방식으로 인증하지만 Access Token 뿐만 아니라 (JWT 방식의 유저 정보를 담고 있는) Id Token을 추가로 받게 된다.
출처
https://www.websiterating.com/ko/password-managers/what-is-2fa-mfa/
https://www.youtube.com/watch?v=Mcyt9SrZT6g&ab_channel=theroadmap
https://smjeon.dev/web/sticky-session/
https://www.okta.com/identity-101/what-is-token-based-authentication/
https://blog.soomgo.com/blog/jwt-for-all/
https://yonghyunlee.gitlab.io/temp_post/oauth-Implicit/
https://showerbugs.github.io/2017-11-16/OAuth-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C
https://sowells.tistory.com/182
'software engineering > frontend' 카테고리의 다른 글
CSS 방법론 그리고 Utility First CSS (1) | 2023.01.17 |
---|---|
단방향, 양방향 바인딩 (0) | 2023.01.16 |
브라우저의 동작원리 (0) | 2023.01.07 |
웹 접근성(a11y)과 storybook addon (0) | 2023.01.06 |
Goodbye, useEffect - David Khourshid (0) | 2022.12.05 |