2023/09/21 [TIL] DRF 인증 방식

장현웅·2023년 9월 21일
0

🥚 인증의 필요성


클라이언트가 요청을 보냈을 때, 그 클라이언트가 누구인지 정확히 알지도 못하는데 아무 정보나 제공하게 되면 그것이 바로 유출이 되는 것 ㅋㅋ

그래서 프론트엔드에서 사용자가 누군지에 대한 정보를 서버에 보내줘야하고, 서버는 그 정보를 바탕으로 사용자에게 맞는 데이터를 제공해야한다.

DRF는 다양한 애플리케이션 요구 사항을 충족하기 위해 여러 가지 인증 방식을 제공한다. 각각의 장단점이 있고 쓰임세도 있지만

이번 포스팅에는 몇몇 DRF 인증 방식에 대해서 가볍게 알아보려고 한다.

🐣 DRF 인증 방식 - Basic Authentication


Basic Authentication(기본 인증)은 웹 애플리케이션에서 사용자를 인증하기 위한 간단한 인증 방식 중 하나로, 사용자 이름과 비밀번호를 HTTP 요청 헤더에 인코딩하여 전송하고, 서버에서 해당 정보를 검증하여 사용자를 인증한다.

단점은 계정 정보를 매번 요청에 넣어서 보내기에는 보안에 너무 취약하여 만약 헤커가 HTTP 요청을 가로채면 사용자 개인 정보를 빼갈 수도 있다.

HTTPS 연결로 HTTP 요청을 암호화하여 보안을 높일 수도 있지만 실제 서비스에서는 잘 사용하지 않는 방식이다.

🐤 DRF 인증 방식 - Session Authentication


Session Authentication(세션 인증)은 웹 애플리케이션에서 사용자의 로그인 상태를 유지하고 관리하기 위한 방식으로, 서버 측에서 사용자 정보를 저장하고, 클라이언트는 세션 식별자를 쿠키를 통해 전달하여 세션을 식별한다.

[ 최초 로그인 ]

  • 순서
  1. 사용자가 최초 로그인을 함.
  2. 서버에서 사용자 계정 정보를 db에서 조회
  3. 사용자가 검증되면, 사용자의 고유 세션 ID값을 부여하고 사용자 계정 정보 세션을 생성하고 세션 저장소에 저장
  4. 사용자의 세션 ID가 포함된 쿠키를 서버로 전달
  5. 클라이언트에게 응답과 함께 헤더에 세션 ID가 포함된 쿠키를 넣어 반환
  6. 클라이언트의 브라우저에 세션 ID가 담긴 쿠키 저장

[ 이후 인증이 필요한 데이터 CRUD 요청 ]

  • 순서
  1. 사용자가 인증이 필요한 데이터 요청에 세션 ID가 저장된 쿠키를 헤더에 실어서 보냄.
  2. 서버에서는 클라이언트로부터 받은 쿠키를 확인하고 세션 ID를 추출
  3. 세션 저장소에서 해당 세션 ID와 사용자 세션 정보 조회 및 검증
  4. 검증되면 사용자의 데이터 요청 처리
  5. 사용자에게 맞는 요청 결과 응답으로 보내줌.
def signin(request):
    # 로그인 페이지 함수 입니다.
    if request.method == "GET":
        return render(request, 'user/signin.html')
    elif request.method == "POST":
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('/')
        else:
            return render(request, 'user/signin.html')
    else:
        return HttpResponse("Invalid request method", status=405)

이 코드에서는 세션 ID와 쿠키가 사용되고 있다.
1. 사용자가 로그인을 시도하면 POST 메서드를 통해 사용자가 제출한 아이디(username)와 비밀번호(password)가 서버로 전송된다.
2. 서버는 authenticate 함수를 사용하여 사용자의 인증을 시도한다. 만약 사용자가 제공한 아이디와 비밀번호가 유효하면, 세션 및 쿠키를 생성하고 사용자를 로그인 상태로 만든다.
3. signin 함수에서는 사용자의 로그인을 시도했고!! 이 함수와는 별개로 장고 내장 함수인 login 함수를 호출하여 사용자를 로그인 상태로 변경하고, 이 과정에서 세션 ID 및 쿠키가 설정된다.
4. 로그인에 성공하면 사용자는 홈페이지(/)로 리디렉션된다. 이때 세션 ID나 쿠키는 브라우저에 저장되며, 사용자가 로그인한 상태를 유지할 수 있도록 한다.

장점

  • 서버 측에서 사용자 정보를 안전하게 관리하므로 비교적 안전
  • 사용자 식별 및 로그인 상태 유지에 유용

세션 방식의 한계

현대 사회에서 세션 방식은 한계가 있다.

  • 다중 기기 및 다중 브라우저 지원의 어려움 : 세션 방식은 주로 단일 브라우저에서의 사용을 가정하고 있기 때문에 만약 한 사용자가 브라우저, 핸드폰, 아이패드 같이 여러 기기에서 로그인을 할 경우엔 세션 공유와 관리에 어려움이 있다.
  • RESTful API와의 호환 어려움 : 현대 웹 애플리케이션에서는 RESTful API를 사용하는 경우가 많은데, 세션 방식은 상태 정보를 유지하기 때문에 stateless하지 않아서 RESTful API와 잘 호환되지 않는다.
  • 보안 이슈 : 서버를 해킹하기는 어렵지만 만약 서버가 해킹된다면 데이터 유출의 위험이 있다. 또한 세션 공격(CSRF, Session Fixation 등)에 취약할 수 있다.
  • 세션 관리 부하 : 세션 데이터를 서버에서 관리해야 하므로 서버 자원을 사용한다. 즉 서버에서 세션 저장소의 공간만큼 더 공간을 쓰게 되고 자연스럽게 부하도 높아진다.

이 방식은 쿠키를 매개로 인증하는 방식이다. 세션 ID가 담긴 쿠키는 사용자 정보를 얻기 위한 열쇠라고 생각하면 된다.

'이 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 노출된 쿠키에 든 세션 ID는 그냥 무의미한 값이다' 라고 생각할 수 있지만 만약 해커가 훔친 세션 ID로 HTTP 요청을 보내면 서버의 세션 저장소에서는 세션 ID만으로 사용자를 식별하기 때문에 사용자를 오인해서 계정 정보가 노출될 수 있다.

이를 해결하는 방법으로는,

HTTPS를 사용해서 HTTP요청을 암호화하여 HTTP 요청이 노출되어도 안의 정보를 읽기 힘들게 하거나 세션에 유효시간을 넣어주는 방법이 있다.

Session

서버 측에서 사용자 정보를 안전하게 관리하고 저장하는 메커니즘으로 클라이언트는 세션 식별자를 쿠키를 통해 받아 저장하고, 서버는 이 세션 식별자를 사용하여 사용자를 식별한다.

클라이언트 측에 저장되는 작은 데이터 조각으로, 클라이언트 브라우저에 저장된다. 주로 사용자 식별 및 상태 유지를 위해 사용되며, 세션 식별자를 클라이언트에게 전달할 때 사용된다.

이러한 한계들 때문에 현대의 웹 애플리케이션은 세션 방식보다는 상태를 보존하지 않는 방식(stateless)과 토큰 기반의 인증(Authentication Tokens) 방식을 선호하며, RESTful API와의 호환성을 강조하는 추세가 있다.

특히 모바일 애플리케이션과 다양한 플랫폼 간의 통신을 간소화하고 확장성을 향상시키기 위해 토큰 기반의 인증 방식(JSON Web Tokens, OAuth)이 많이 사용된다.

🐥 DRF 인증 방식 - Token Authentication


Token Authentication(토큰 인증)은 웹 애플리케이션 및 API에서 사용자 인증을 관리하기 위한 방법 중 하나이다. Token(토큰) 은 변조할 수 없는 인증 파일로, 사용자가 로그인하면 서버에서 고유한 토큰을 생성하고, 이 토큰을 클라이언트(예: 웹 브라우저 또는 모바일 앱)에게 제공한다.

사용자는 이 토큰을 안전하게 브라우저의 쿠키나 로컬스토리지와 같은 로컬 저장소에 전송하고 저장한다. 쿠키와 마찬가지로 사용자는 새로운 API 요청이 있을 때마다 이 토큰을 서버에 토큰을 함께 전송한다.

서버는 클라이언트로부터 받은 토큰의 서명을 확인하고, 유효한 경우 요청을 승인한다.

비밀 키를 사용하여 서버에서 생성되고

[ 최초 로그인 ]

  • 순서
  1. 사용자가 서버에 로그인 요청을 보냄.
  2. 서버에서 사용자 계정 정보를 db에서 조회
  3. 사용자가 검증되면, 로그인을 승인하고 고유한 토큰을 생성 (로그인 할때마다 생성)
  4. 사용자에게 반환되고, 일반적으로 클라이언트 측에서 저장됨

[ 이후 인증이 필요한 요청 ]

  • 순서
  1. 사용자가 인증이 필요한 요청을 보낼 때, 토큰을 요청 헤더에 포함하여 서버에 전달
  2. 서버는 클라이언트로부터 받은 토큰이 유효한지 확인 (토큰 서명이나 유효 기간 등 확인)
  3. 토큰이 유효한 경우, 토큰에 포함된 사용자 ID를 사용해서 데이터 요청 처리
  4. 요청 처리 결과 클라이언트에게 반환

토큰을 받는 동안 서버는 사용자가 누구인지 조회 하지 않고 단순히 토큰의 유효성에 따라 사용자의 요청을 승인한다. 이 말은 즉, 서버는 사용자가 로그인했는지 안했는지 알 수가 없다.

토큰은 사용자가 자격 증명을 보내야 하는 횟수를 줄이고 싶을 때 유용할 수 있다. 서버 간 연결의 경우 자격 증명을 사용하는 것이 어려워지며 토큰이 이 문제를 해결할 수 있다. 또한 토큰을 사용하는 서버는 사용자의 요청을 승인하기 위해 모든 세션 세부 정보를 지속적으로 확인할 필요가 없기 때문에 성능을 향상시킬 수 있다.

그 외 장점

  • Token Authentication은 서버 측에서 상태를 저장하지 않으므로 서버 부하를 줄일 수 있다.
  • 토큰은 웹, 모바일 앱, API 등 다양한 플랫폼에서 사용할 수 있어 다양한 클라이언트 환경에서 호환성을 유지할 수 있다.
  • 서버 측에 세션 상태를 저장하지 않는 무상태(Stateless) 특성이 있어 RESTful API와 잘 어울린다.

단점

  • 토큰을 유출되지 않도록 안전하게 저장하고 관리해야 한다.
  • 가상의 공격자가 유효한 토큰을 얻으면 서버 데이터베이스에 무제한으로 액세스할 수 있다.
  • 서버가 사용자 상태를 저장하지 않기 때문에 로그아웃, 토큰 갱신과 같은 기능에 대한 추가 로직이 필요할 수 있다.
  • 토큰의 유효성을 확인하는 로직이 필요하다.
  • 인증 내용이 클라이언트에 저장되기 때문에 서버에서는 세션 방식과 같은 특정 보안 작업을 할 수 없다.

활용

  • 웹 애플리케이션 및 모바일 앱의 사용자 인증 및 권한 부여.
  • RESTful API의 보안 인증 및 접근 제어.
  • 사용자가 여러 기기 또는 클라이언트에서 동시에 로그인할 수 있는 환경.

특히 JWT(JSON Web Tokens)는 Token Authentication의 한 형태로 사용되며, 토큰에 JSON 형식의 정보를 포함하고 서명을 통해 검증된다.

🐓 Local Storage VS Cookies


Cookies (쿠키)

  • 형태
    • Key와 Value 쌍으로 데이터를 저장한다.
    • 데이터는 문자열 형태로 저장되지만, 서버에서 설정된 추가 속성도 가질 수 있다.
    • 각 쿠키는 도메인, 경로, 만료 날짜 등의 속성을 가진다.
    • 세션 쿠키와 영구 쿠키로 구분되며, 세션 쿠키는 브라우저를 닫으면 삭제되고, 영구 쿠키는 설정된 만료 날짜까지 유지된다.
  • 장점
    • 서버 및 클라이언트 간에 데이터를 주고받을 때 자동으로 전송된다.
    • 쿠키에는 HttpOnly 및 Secure와 같은 보안 옵션을 적용하여 보안을 강화할 수 있다.
  • 단점
    • 쿠키에 저장할 수 있는 데이터 용량은 일반적으로 4KB로 제한된다.
    • 복잡한 데이터 저장에는 부적합하다.
  • 사용하기 좋은 케이스
    • 세션 관리 및 사용자 추적에 적합 (ex. 로그인 상태 유지, 세션 식별)
    • 광고 타겟팅, 행동 분석, 방문자 통계 등 분석 및 추적 용도로 사용될 수 있다.
    • 세션 기간 동안 데이터 공유 또는 다른 페이지 간 정보 전달에 활용된다.

Local Storage (로컬 스토리지)

  • 형태
    • Key와 Value 쌍으로 데이터를 저장한다.
    • 데이터는 문자열(string) 형태로 저장되고 브라우저 세션 간에 영구적으로 유지된다. (= 데이터가 지속적이고 만료 날짜가 없다.)
  • 장점
    • 데이터는 브라우저를 닫더라도 영구적으로 보존된다.
    • 데이터 용량은 일반적으로 5MB 정도로 쿠키보다 더 큰 용량의 데이터를 저장할 수 있다.
    • 데이터를 JavaScript를 사용하여 쉽게 읽고 쓸 수 있다.
      • .getItem : 데이터 수정, 추가 등 데이터에 엑세스하고 값을 가져올 때
      • .setItem : 읽기 전용
      • .removeItem : 로그아웃 할 때, 로컬 스토리지의 데이터 삭제
    • 클라이언트 측에서 데이터를 쉽게 저장하고 관리할 수 있습니다.
  • 단점
    • 로컬 스토리지는 JavaScript로 액세스할 수 있으므로, 악의적인 코드가 액세스하면 보안 위험성이 있다.
    • 쿠키처럼 서버로 자동으로 전송되지 않기 때문에 AJAX 요청과 함께 수동으로 토큰을 보내야한다.
  • 사용하기 좋은 케이스
    • 사용자 설정, 환경 관리 (테마, 언어 등)에 적합
    • 로그인 상태 유지 및 세션 관리에 사용될 수 있다.
    • 장바구니, 임시 작업 데이터 등을 저장하는 데 유용
    • 오프라인 애플리케이션 데이터 캐싱에 활용될 수 있다.

데이터의 지속성과 용량 요구 사항을 고려하여 로컬 스토리지 또는 쿠키를 선택한다.

중요한 데이터나 인증 정보를 저장해야 할 경우 보안 고려 사항을 고려하여 적절한 방식을 선택한다.

세션 관리에 쿠키를 사용하고 사용자 설정을 로컬 스토리지에 저장할 수 있는 것 처럼 필요에 따라 두 기술을 혼합해서 사용할 수 있다.

일반적으로 토큰은 클라이언트 측에 사용 용도와 보안 요구 사항에 따라 로컬 스토리지에 저장되거나, 쿠키에 저장되기도 한다.
HttpOnly 쿠키 속성을 사용하면 HTTPS 연결을 통해서만 전송되고 중요한 정보를 Javascript로부터 숨길 수 있기 때문에 쿠키를 사용하는게 좋고,
더 큰 데이터를 저장해야 하거나 JavaScript로 쉽게 액세스해야 하는 경우에는 로컬 스토리지를 사용하는게 좋다.


🥚🐣🐤🐥🐓🐔

0개의 댓글