Dev_articles/General

[로그인?] 다양한 인증 수단들

humblEgo 2021. 4. 11. 12:05

들어가며

안녕하세요! ✋ 문득 로그인이 무엇인지 제대로 알고있지 못하다는 생각이 들었습니다. 관련 지식을 구조화할 겸 가볍게 포스팅해봅니다!

 

👨🏻‍💻 로그인은 무엇일까?

In computer security, logging in (or logging on, signing in, or signing on) is the process by which an individual gains access to a computer system by identifying and authenticating themselves. - Wikipedia

로그인은 자원에 접근할 수 있는 권한을 획득하기 위해 인증과 인가를 받는 절차입니다. 로그인을 쉽게 접할 수 있는 웹 서비스를 예로 들어봅시다.

웹 서비스는 보통 클라이언트가 서버에 자원을 요청하고, 서버가 적절하게 자원을 응답하는 형태로 운영됩니다.

만약 클라이언트가 다양하고, 각 클라이언트가 요청할 수 있는 자원이 제각각 다르다면, 서버 입장에서는 자원을 적절하고 유효한 클라이언트에게 전달해야 한다는 이슈가 생깁니다. 이를 위해서 서버는 클라이언트의 자원 요청에 대해 인증과 인가 과정을 거칩니다.

  • 인증(Authentication)
    • 어떤 정보가 어떤 자에게 유일하게 속한다는 사실을 확인하고 이를 증명하는 행위
    • ex) ID, 패스워드 입력, 휴대폰 번호 인증, 이메일 인증, 지문 인증 등등
  • 인가(Authorization)
    • 인증된 사용자에 대한 자원 접근 권한을 확인하는 과정
    • ex) 신원이 확인된 유저의 보안 레벨이 자원 요청이 가능한지 확인

이 포스팅에서는 인증에 대해 자세히 알아보겠습니다.

 

🛠 다양한 인증 수단들

인증 수단은 다양하지만, 큰 범주로 보면 3가지-지식, 소유, 신체로 분류할 수 있습니다.

  1. 지식
    • 내가 알고 있는 것
    • ID와 패스워드, 어릴 적 별명 등등
    • 분실의 우려는 없지만 '추정 공격'에 취약해서 보안성이 다소 낮은 편에 속함.
  2. 소유
    • 내가 가진 것
    • 인증서, 보안카드, OTP, 휴대폰 인증문자, 인증 메일 등등
    • 보안성이 높지만 분실의 위험이 있음.
  3. 신체
    • 지문, 음성, 홍채, 안면 형태, 심박수 등
    • 보안성이 높고 분실의 위험은 낮지만 저장해 둔 정보가 유출되고 나면 대체하여 인증할 수단이 없다는 단점이 있음.

보통 금전 거래 등 심각한 일이 일어나지 않는 인증에 대해서는 '지식'을 인증수단으로 하여 1차 인증만 하는 경우가 많습니다. 하지만 심각한 일이 일어날 소지가 있다면 2 요소 인증(Two Factor Authentication, 2FA)을 하는 편이 보안상 바람직합니다.

2 요소 인증은 단순히 인증 절차를 2번 거치는게 아닙니다. 서로 다른 분류의 인증 수단을 2가지 이상 거쳤을 때 비로소 2 요소 인증이라고 할 수 있습니다. 예시를 보면 이해하기 쉽습니다!

  • ex 1) 아이디와 비밀번호를 검증하고 나서 어릴적 별명을 검증했다면?
    • 인증 수단으로 '지식'을 2번 활용했으므로 2 요소 인증이라 할 수 없음.
  • ex 2) 아이디와 비밀번호를 검증하고 나서 휴대폰으로 보낸 SMS 인증번호를 검증했다면?
    • '지식'과 '소유'를 차례로 활용했으므로 2 요소 인증이라 할 수 있음.

실제로 제가 진행했던 트렌센던스 프로젝트에서는 아이디/비밀번호 검증 외에 이메일 인증번호 검증을 통해 '2 factor authentication'을 구현했습니다.

image

 

😇 ..매번 이렇게 인증하라고..?

인증을 구현해내더라도 웹 서비스에서는 고려해야할 문제가 더 있습니다.

웹 서비스에 주로 쓰이는 HTTP 프로토콜은 기본적으로 요청에 대해 응답을 받으면 연결이 끊어지고(connectionless), 통신이 종료되면 어떠한 상태 정보도 남지 않습니다(stateless). 따라서 따로 처리를 해주지 않으면 서버 입장에서는 자원을 요청한 클라이언트가 이미 인증을 거쳤는지 확인할 방법이 없습니다.

그럼 클라이언트가 매 자원을 요청할 때마다 인증을 반복해야할 수 있고, 이로 인해 1) 클라이언트 입장에서는 핵 귀찮을 수 있고(UX 문제) 2) 서버 입장에서도 과도한 인증을 위해 자원을 써야할 수 있습니다(비효율 문제).

이 문제를 해결하기 위한 수단으로 쿠키와 세션을 사용한 서버 기반 인증방식과 토큰 기반 인증방식을 고려할 수 있습니다.

쿠키(Cookie)

개념

    • 쿠키는 웹 브라우저 또는 로컬 디스크에 키-값 형태로 저장되는 작은 데이터 파일입니다.
    • 서버는 Set-Cookie 응답 헤더를 통해 클라이언트 측 브라우저 로컬에 쿠키를 생성하라고 요청할 수 있습니다. (만료기간, 도메인 등 옵션 설정 가능)
    • 쿠키를 인증 상태 유지에 활용할 때는 아래 과정을 거칩니다.
1. 클라이언트가 로그인하며 인증 정보를 요청 헤더에 담아서 서버에 전달 
2. 서버가 인증된 사용자 정보를 담은 쿠키를 생성하라는 내용을 `Set-Cookie` 응답 헤더에 담아서 응답 
3. 클라이언트는 브라우저에 쿠키를 생성하고, 이후 쿠키가 만료될 때까지 요청 헤더에 쿠키 정보를 넣어서 요청 
4. 서버는 요청 헤더에 포함된 쿠키 정보를 통해 클라이언트 인증 여부 판단

 

장점

  • 간편하기 때문에 민감하지 않은 정보를 포함한 상태 유지에 활용하기 편합니다. ex) 오늘 하루 보지 않기
  • 서버의 처리가 딱히 필요없어서 세션보다 처리 속도가 빠릅니다.

단점

  • 쿠키를 저장할 때 암호화를 한다고 하더라도 유의미한 사용자 정보가 클라이언트 측에 저장되므로 보안이 취약합니다.
  • 하나의 도메인 당 20개의 값만 가질 수 있고, 하나의 쿠키 값은 4096 Byte까지만 저장 가능하며, 총 300개까지만 쿠키를 저장할 수 있는 등의 제약사항이 있습니다.
  • 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 있기 때문에 여러 도메인에서 관리하기 어렵습니다.

세션(Session)

개념

  • 세션은 클라이언트와 웹 서버 간의 네트워크 연결이 지속적으로 유지되고 있는 상태를 뜻합니다.
  • 세션의 만료 시점은 보통 브라우저가 종료될 때까지 입니다.
  • 세션을 인증 상태 유지에 활용할 때는 아래 과정을 거칩니다.
1. 클라이언트가 로그인하며 인증 정보를 요청 헤더에 담아서 서버에 전달 
2. 서버가 인증된 유저에 고유한 ID 값을 부여하여 세션 저장소에 저장한 후, Session ID를 발행 
3. 서버가 Session ID를 쿠키에 저장하여 클라이언트에 응답 
4. 이후 클라이언트는 요청 헤더에 쿠키를 담아서 자원 요청 
5. 서버는 요청에 포함된 쿠키의 Session ID로 세션을 불러와 유효한지 확인 및 인증
  • 세션 저장소는 DB에 저장하기도 하고, REDIS 등 메모리를 사용하기도 합니다.
  • 결국 세션도 쿠키를 사용하지만, 사용자 정보 파일을 브라우저에 저장하는 것이 아니라 서버 측에 저장한다는 측면에서 다릅니다.

 장점

  • 쿠키 자체에 유의미한 사용자 정보가 저장되지 않으므로 보안상 이점이 있습니다.

단점

  • 서버 메모리 or DB에 정보를 저장하기 때문에 세션이 많아질 경우 용량이 부족해질 수 있습니다.
  • Session ID를 검증하는 데 일일이 세션 저장소에 접근해야하므로 서버 부하가 커질 수 있습니다.
  • 서버가 여러개가 존재한다면 각 서버가 동일한 세션 저장소를 참조하기 어렵습니다. 매 요청마다 다른 서버가 응답한다면, 새로 접속한 서버의 세션 저장소에 인증 정보가 없어서 계속 인증을 새로 해야할 수도 있습니다. sticky 세션(같은 서버에 세션을 계속 연결하는 방식)을 사용하여 억지로 해결할 수 있기는 하지만, 번거롭고 비효율이 발생합니다. 결국 서버 확장성(scalability)이 나빠집니다.

토큰(Token)

개념

  • 서버가 싸인한 토큰을 이용하여 인증을 수행하는 방식입니다.
  • 토큰을 인증 상태 유지에 활용할 때는 아래 과정을 거칩니다.
1. 클라이언트가 로그인하며 인증 정보를 요청 헤더에 담아서 서버에 전달 
2. 서버는 사용자를 검증하고, 유효할 경우 signed 토큰을 발급하여 클라이언트에 전달 
3. 클라이언트는 토큰을 저장해두고, 자원 요청시마다 해당 토큰을 요청 헤더에 담아서 서버에 전달 
4. 서버는 토큰을 검증하여 인증 여부 판단

장점

  • 서버의 부담이 줄어듭니다. 세션 정보를 서버에 저장할 필요 없이 서버는 전달 받은 토큰을 검증만 하면 되기 때문입니다.
  • 따로 쿠키 매니저를 둘 필요가 없기 때문에 모바일 애플리케이션에서 사용하기 편리합니다.
  • 서버 확장에 용이합니다. 전달 받은 토큰만 검증하면 되므로, 굳이 세션이 저장된 서버가 아니더라도 클라이언트의 인증 여부를 확인할 수 있습니다.

단점

  • 세션/쿠키의 경우 session ID가 변질되었다고 판단되면 해당하는 세션을 지우면 되지만, 토큰은 한 번 발급되면 유효기간이 완료될 때까지는 계속 사용이 가능합니다. 따라서 토큰이 공격자에게 탈취되었다면, 공격자는 토큰이 만료될 때까지 서버에 요청을 할 수 있습니다.
  • API 호출시 매 호출마다 토큰 데이터를 서버에 전달해야 하는데, payload에 추가되는 name과 value 쌍인 클레임(claim)이 많아질 수록 토큰 길이가 길어져서 대역폭 낭비로 이어질 수 있습니다.

👨🏻‍💻 마치며

내용이 길어져서 보안 관련된 내용(XSS, CSRF 공격, 단방향/양방향 암호화)과 토큰과 관련된 내용(Access token/Refresh token, Sliding sessin, token 저장 장소, JWT 방식, OAuth) 등 흥미로운 주제는 따로 포스팅해보겠습니다.

참고