Javascript

OAuth 배우기 전에 배우는 웹 인증의 세계 - Basic, Digest, 세션, 토큰 인증 비교

드리프트2 2024. 7. 17. 21:23

 

안녕하세요!

 

오늘은 웹 애플리케이션 개발에 있어 가장 중요한 인증·인가의 기초와 OAuth를 배우기전에 웹 인증의 종류에 대해 비교해서 알아보겠습니다.

인증·인가의 기초

인증과 인가의 차이

인증이란 "사용자가 누구인지"를 확인하는 프로세스이며, 영어로 Authentication이라고 표기합니다.


반면에, 인가란 "사용자가 특정 권한을 가지고 있는지"를 확인하는 프로세스이며, 영어로 Authorization이라고 표기합니다.

 

예를 들어,

  • 은행 계좌를 개설할 때는 운전면허증 등을 제출해서 본인임을 확인하는데, 이는 운전면허증을 사용해 계좌를 개설하는 사람이 "누구인지"를 확인하는 것이므로 인증(Authentication)에 해당합니다.
  • 반면에 기차에 탑승할 때는 개찰구에 표를 통과시키죠. 이는 표를 사용해 기차에 탑승할 "권한이 있는지"를 확인하는 것이므로 인가(Authorization)에 해당합니다.

엔지니어에게 익숙한 예로 말하자면, 자격 정보를 사용해 사용자를 특정하는 로그인 기능은 인증이고, 관리자나 일반 사용자 등의 역할에 의한 접근 제어는 인가에 해당합니다.

인증에 기반한 인가

실제 애플리케이션에서는 인증 프로세스에서 사용자가 누구인지 확인한 후에, 인가 프로세스에서 해당 사용자가 특정 권한을 가지고 있는지 확인하는 식으로 인증 후에 인가가 세트로 이루어지는 경우가 많습니다.

 

예를 들면,
"로그인 기능으로 인증하여 사용자를 특정하고, 그 사용자와 연결된 역할을 가져와서 그 역할을 기반으로 인가하여 권한이 있는지 확인한다"는 케이스입니다. 실제 시스템에서는 이 케이스처럼 인증 프로세스에서 특정한 사용자에 대해, 인가 프로세스에서 권한을 확인하는 인증에 기반한 인가가 이루어지는 경우가 많습니다.

인증의 3요소

인증 정보(본인 확인을 위해 필요한 정보)는 크게 세 가지 요소로 나눌 수 있습니다.

  • 지식 정보(What you know)
    • 이메일 주소·비밀번호 등 본인만 알고 있는 정보
  • 소유 정보(What you have)
    • 운전면허증이나 여권 등 본인만 가지고 있는 정보
  • 생체 정보(What you are)
    • 지문이나 얼굴 등 본인의 생체에 갖추어진 고유한 정보

위 중 1요소를 사용해 인증하는 것을 단일요소 인증, 2요소 이상을 기반으로 인증하는 것을 다중요소 인증이라고 합니다.

 

인증 단계를 2단계로 나누는 2단계 인증이라는 것도 있지만, 반드시 다른 요소를 조합하는 것은 아닙니다.

다양한 인증 방법

현재 웹 애플리케이션에서 인증하는 방법은 다양합니다.

 

여기서는 주요 인증 방법에 대해 설명하겠습니다. 아래 각각의 플로우에서는 클라이언트를 브라우저로 가정하고 기재하고 있지만, HTTP 프로토콜을 이용할 수 있는 클라이언트라면 브라우저 이외에도 적용할 수 있습니다.

Basic 인증

HTTP가 제공하는 접근 제어 구조를 사용한 인증 방식 중 하나로 HTTP 기본 인증이라고도 불립니다.

 

Basic 인증의 플로우

  1. 초기 요청
    • 사용자가 접근 제한이 걸려있는 리소스에 접근하면, Basic 인증을 구현한 서버는 HTTP 401 (Unauthorized)를 반환하고, 브라우저에 인증이 필요하다는 것을 알립니다. 응답에 포함된 WWW-Authenticate 헤더는 인증의 종류가 Basic 인증임을 나타냅니다.
  2. 인증 정보 전송
    • 이 응답을 받은 브라우저는 인증용 다이얼로그를 표시합니다. 그 다이얼로그에 사용자가 사용자명과 비밀번호를 입력하면, Authorization 헤더에 사용자 정보를 설정하여 서버에 HTTP 요청이 전송됩니다. 이때 설정되는 사용자 정보는 사용자명과 비밀번호를 콜론(:)으로 결합하고 Base64 인코딩한 문자열이 됩니다.
  3. 인증 처리
    • 2의 HTTP 요청을 받은 서버는 Authorization 헤더에 설정된 사용자 정보를 Base64 디코딩하여 얻습니다. 그 후 서버 측에 저장되어 있는 사용자 정보와 대조하여 인증 결과를 브라우저에 반환합니다.

보통 브라우저는 한 번 Basic 인증에 성공한 사용자 정보를 캐시하여, 동일한 리소스에 접근할 때 자동으로 Authorization 헤더에 포함하여 서버에 전송합니다.

 

그렇기 때문에 사용자는 요청할 때마다 사용자 정보를 입력할 필요가 없습니다.

realm이란?

플로우 다이어그램을 보면 서버로부터의 인증 요청 응답에서 WWW-Authenticate 헤더에 realm(렐름)이라는 값이 설정되어 있는 것을 알 수 있습니다.

 

이는 인증이 필요한 리소스의 범위에 이름을 붙이기 위한 것으로, 렐름마다 필요한 인증 정보를 정의할 수 있습니다.


예를 들어, 서버 상에서 "리소스 A와 B는 realm="Realm1""으로, "리소스 C와 D는 realm="Realm2""라고 설정되어 있다고 합시다.

 

이때 리소스 A에 처음 접근하면,

WWW-Authenticate: Basic realm="Realm1"

 

이라는 응답이 반환되고, 사용자는 Realm1에 연결된 인증 정보를 입력합니다.

 

이때 인증 정보가 브라우저에 캐시되므로, 리소스 B에 접근할 때 사용자가 다시 인증 정보를 요구받지 않는 상태가 됩니다.

 

그러나 리소스 C, D에 접근한 경우에는 렐름이 다르므로,

WWW-Authenticate: Basic realm="Realm2"  

 

라는 응답이 반환되고, 사용자는 Realm2에 연결된 인증 정보의 입력을 요구받습니다.

 

Basic 인증의 특징

  • 구현이 용이
    • 보통은 (Apache나 Nginx 등의) 웹 서버 설정으로 쉽게 Basic 인증으로 리소스에 접근 제한을 걸 수 있습니다.
  • 낮은 보안성
    • 사용자명과 비밀번호를 Base64 인코딩하지만, 이는 암호화가 아니라 가역적인 변환이므로 유출이나 변조의 리스크가 있습니다. 그렇기 때문에 Basic 인증을 사용할 경우에는 HTTPS/TLS로 암호화하는 것이 권장됩니다.

Digest 인증

Digest 인증도 HTTP가 제공하는 접근 제어 구조를 사용한 인증 방식 중 하나입니다.


Basic 인증에서는 사용자 정보를 암호화하지 않고 전송하는 취약한 구조였지만, Digest 인증에서는 사용자 정보를 암호화하여 서버에 전송하는 구조로 되어 있어, Basic 인증보다 보안성이 높은 인증 방식이 되어 있습니다.

 

Digest 인증의 플로우

  1. 초기 요청
    • 사용자가 접근 제한이 걸려있는 리소스에 접근하면, Digest 인증을 구현한 서버는 HTTP 401 (Unauthorized)를 반환하고, 브라우저에 인증이 필요하다는 것을 알립니다. 응답에 포함된 WWW-Authenticate 헤더는 인증의 종류가 Digest 인증임을 나타냅니다.
    • 또한 이때 Basic 인증에는 없었던 nonce라는 서버에서 생성한 랜덤한 문자열을 WWW-Authenticate 헤더에 포함시킵니다.
  2. 인증 정보 전송
    • 이 응답을 받은 브라우저는 인증용 다이얼로그를 표시합니다. 그 다이얼로그에 사용자가 사용자명과 비밀번호를 입력하면, Authorization 헤더에 다음 파라미터를 설정하여 서버에 HTTP 요청이 전송됩니다.
      파라미터 설명
      username 사용자가 입력한 사용자명
      response 사용자명과 비밀번호에 nonce 값을 조합하여 암호화한 문자열
      ※ 기본적으로는 MD5라는 암호화 알고리즘이 사용됨
      nonce 서버로부터 받은 랜덤 생성 문자열
  3. 인증 처리
    • 2의 HTTP 요청을 받은 서버는 Authorization 헤더의 username이나 nonce와 서버에 저장되어 있는 비밀번호를 조합하여 암호화합니다. 이때의 암호화는 클라이언트에서의 response 값 생성에 사용된 암호화 알고리즘이 사용됩니다. 그 암호화한 결과와 Authorization 헤더의 response 값을 비교하여 일치하면 인증 성공으로 합니다.

Basic 인증과 마찬가지로 인증 정보가 캐시되므로, 리소스에 접근할 때마다 사용자 정보를 입력할 필요는 없습니다.

Digest 인증의 특징

  • 구현이 용이
    • Basic 인증과 마찬가지로, 보통은 (Apache나 Nginx 등의) 웹 서버 설정으로 쉽게 Digest 인증으로 리소스에 접근 제한을 걸 수 있습니다.
  • Basic 인증보다 높은 보안성
    • 비밀번호를 평문으로 전송할 필요가 없는 만큼, Basic 인증보다 유출이나 변조의 리스크는 적습니다.
    • 그러나 암호화의 강도 문제 등 Digest 인증에도 취약한 점이 남아 있는 듯하므로, 보통은 더 보안성이 높은 인증 방식을 사용하는 것이 좋을 것 같습니다.

 

세션 기반 인증

 

세션 기반 인증은 웹 애플리케이션에서 많이 사용되는 인증 방식 중 하나입니다.


브라우저에서 서버로의 요청마다 사용자 정보를 전송하는 Basic 인증이나 Digest 인증과는 달리, 세션 ID라는 사용자 정보와 연결된 ID를 요청에 포함합니다.

 

세션 기반 인증의 플로우


세션 ID를 저장하는 세션 스토어로 데이터베이스를 사용하고 있지만, 서버 상의 파일이나 Redis 등 다른 세션 스토어를 사용할 수도 있습니다.


세션 기반 인증은 "사용자가 로그인한 후에 로그인 상태를 유지하는 방법"이므로, 로그인 방법은 규정되어 있지 않습니다.

 

  1. 로그인
    • 사용자가 로그인 페이지에 접근하여 사용자명과 비밀번호 등의 사용자 정보를 입력합니다. 서버에 POST 요청이 전송되고, 서버는 받은 사용자 정보를 데이터베이스에 문의합니다.
  2. 세션 ID 생성
    • 브라우저에서 받은 사용자 정보와 데이터베이스 상에 저장되어 있는 사용자 정보가 일치하면 인증이 성공하고 서버에서 세션 ID를 생성합니다. 생성한 세션 ID를 데이터베이스에 저장하고, 브라우저에 응답을 반환합니다. 이때 생성한 세션 ID를 Set-Cookie 헤더에 설정합니다. 브라우저가 로그인 성공 응답을 받은 후, 브라우저의 내부 데이터 스토어인 쿠키에 세션 ID를 저장합니다.
  3. 리소스에 접근
    • 다시 서버 상의 리소스에 접근할 때, Cookie 헤더에 쿠키에 저장하고 있는 세션 ID가 자동으로 설정됩니다. 요청을 받은 서버는 세션 ID를 키로 데이터베이스에서 사용자 정보를 얻고, 사용자 정보를 얻는 데 성공하면 리소스를 반환합니다.

세션 기반 인증에서는 한 번 세션 ID가 브라우저의 쿠키에 저장되면 쿠키가 파기될 때까지는 다시 로그인할 필요가 없습니다.

 

세션 기반 인증의 특징

  • 상태 저장(stateful)
    • 세션 기반 인증의 경우, 서버에서 세션과 사용자 정보의 연결을 관리할 필요가 있습니다. 즉, 세션 기반 인증은 서버 측에서 상태를 가질 필요가 있으므로 상태 저장(stateful)인 인증 방식이라고 할 수 있습니다. 또한 서버 측에 상태를 가지게 하므로 확장성에 과제가 있습니다.
  • Basic/Digest 인증보다 높은 보안성
    • Basic 인증이나 Digest 인증에서는 요청마다 사용자 정보가 전송되고 있었습니다. 세션 기반 인증에서는 요청마다 세션 ID만 전송하므로, 더 보안성이 높다고 할 수 있을 것 같습니다.
    • 세션 ID가 도난당한 경우, 다른 사용자의 리소스에 접근할 수 있게 되어 버리므로, 세션의 유효 기한이나 쿠키의 HttpOnly 속성, Secure 속성을 사용하여 세션 ID가 유출되는 리스크를 낮출 수 있습니다.

 

토큰 기반 인증

토큰 기반 인증도 세션 기반 인증과 마찬가지로 웹 애플리케이션에서 많이 사용되는 인증 방식 중 하나입니다.


사용자 정보와 연결된 세션 ID를 사용하여 인증하는 세션 기반 인증과는 달리, 접근 가능한 리소스의 범위(스코프) 정보를 포함한 토큰을 사용하여 인증합니다.

 

"사용자가 로그인한 후에 로그인 상태를 유지하는 방법"이라는 점은 세션 기반 인증과 동일합니다.

 

토큰 기반 인증의 플로우

  1. 로그인
    • 로그인에 대해서는 세션 기반 인증의 플로우에 기재한 플로우와 변함없습니다.
  2. 토큰 발급
    • 서버 상에서 접근 가능한 리소스의 범위(스코프) 정보를 포함한 토큰을 발급합니다. 토큰은 세션 ID와는 다르게 사용자 정보와 연결하여 관리하지 않습니다. 보통은 변조가 어려운 JWT 형식의 토큰을 사용하는 경우가 많습니다. 브라우저가 로그인 성공 응답을 받은 후, 쿠키 등에 토큰을 저장합니다.
  3. 리소스에 접근
    • 다시 서버 상의 리소스에 접근할 때, Authorization 헤더에 Bearer <토큰> 형식으로 토큰을 설정하여 요청을 전송합니다. 요청을 받은 서버는 토큰이 변조되지 않았는지, 유효 기한 내인지를 검증하고 리소스를 반환합니다.

토큰 기반 인증에서는 브라우저에 저장된 토큰이 파기될 때까지는 다시 로그인할 필요가 없습니다.

토큰 기반 인증의 특징

  • 상태 비저장(stateless)
    • 토큰 기반 인증에서는 세션 기반 인증과 달리 서버 상에서 상태를 관리할 필요가 없으므로, 상태 비저장(stateless)인 인증 방식이라고 할 수 있습니다. 그렇기 때문에 확장성도 높아집니다.
  • 토큰을 무효화할 수 없음
    • 세션 기반 인증의 경우, 세션 ID를 서버 측에서 보유하고 있으므로 인증 상태를 무효화할 수 있습니다. 그러나 토큰 기반 인증의 경우, 토큰을 서버 측에서 보유하고 있지 않으므로 인증 상태를 무효화할 수 없습니다. 브라우저에서 보유하고 있는 토큰을 파기하는 것은 할 수 있지만, 토큰 자체가 무효화되는 것은 아니므로 예를 들어 토큰이 유출되어 있었던 경우, 유출된 토큰을 악용하여 부정하게 접근될 리스크가 있습니다.
  • 토큰 유출의 영향 완화 대책
    • 위에서 말한 대로 토큰은 무효화할 수 없으므로, 유출된 경우에 부정 이용될 리스크가 높습니다. 부정 이용의 리스크를 낮추기 위한 대책으로 다음이 고려됩니다.
    1. 토큰의 유효 기한을 짧게 설정하기
      • 토큰 안에 유효 기한 정보를 포함시킬 수 있습니다. 서버 상에서 토큰을 검증할 때, 유효 기한이 지났는지 확인하고, 지났다면 보호된 리소스에 대한 접근을 허가하지 않습니다.
      • 이 유효 기한을 짧게 설정함으로써, 액세스 토큰이 유출된 경우에도 부정 이용되는 영향을 완화할 수 있습니다. 다만 유효 기한을 짧게 설정할수록 사용자가 로그인을 요구받는 횟수가 늘어나므로, 사용자 경험이 저하되어 갑니다. 이를 해결하기 위해 리프레시 토큰을 활용할 수 있습니다.
      • 토큰의 유효 기한이 지난 경우에, 브라우저에서 리프레시 토큰을 전송함으로써 새로운 액세스 토큰을 발급받을 수 있습니다. 토큰의 유효 기한을 짧게 설정해도, 리프레시 토큰의 유효 기한을 길게 함으로써 자주 로그인이 요구되지 않도록 하여 사용자 경험의 저하를 막을 수 있습니다.
    2. 토큰의 블랙리스트 관리
      • 서버 측에서 토큰의 블랙리스트를 관리하는 방법입니다. 무효화하고 싶은 토큰을 블랙리스트에 추가하고, 블랙리스트에 올라가 있는 토큰을 포함한 요청은 보호된 리소스에 대한 접근을 허가하지 않도록 합니다.
      • 다만 서버 측에서 상태를 가질 필요가 없는 상태 비저장(stateless)인 인증 방식이라는 토큰 기반 인증의 메리트가 훼손되고, 확장성이 저하되어 버립니다.