[CPM] 로그인(1)

이리·3일 전
0
post-thumbnail

청양고추마켓은 중고거래 플랫폼입니다.
게시물을 올리고, 채팅을 진행하기 위해서는 인증과 인가를 거친 로그인 기능이 구현되어야합니다.

로그인을 구현하기에 앞서 로그인을 구현하는 방법에 대해 종류별로 알아보고 어떤 방식으로 구현할지 정한 뒤, 구현 단계로 넘어가도록 하겠습니다.


HTTP는 기본적으로 무상태(stateless) 프로토콜이기 때문에 클라이언트와 서버가 요청을 한번 주고받으면 연결이 끊어지고 상태 정보가 유지되지 않습니다. 이러한 특성은 많은 사용자가 동시에 요청을 보낼때 과부하를 방지하는데 유리하지만, 로그인 기능과 같이 상태를 유지해야 하는 경우에는 단점으로 작용합니다.

이 문제를 해결하기 위해, 로그인 상태와 같은 사용자 정보를 유지할 방법이 필요했고, 쿠키와 세션 등의 기술이 등장했습니다.

[ 간단 용어 정리 ]

  • 인증(Authentication): 해당 사용자가 본인이 맞는지 확인
  • 인가(Authorization): 인증된 사용자가 요청한 자원에 접근 가능한지를 결정합니다.

그럼 지금부터 본격적으로 로그인 방식에 대해서 알아보겠습니다.


쿠키란?

웹 접속시 브라우저에 저장되는 텍스트 파일, 브라우저마다 쿠키를 저장하는 전용 공간(브라우저 내 쿠키저장소)이 존재(자동 관리)

쿠키는 만료 기간에 따라 영속쿠키와 세션쿠키로 분류됩니다.

쿠키 로그인 진행 방식

  1. Client → Server: 로그인 폼에 id & pw를 서버에 보냄
  2. Server: 받은 id와 pw를 DB의 정보와 비교해서 인증을 진행 / 인증 성공 시 서버는 쿠키를 생성→ 쿠키는 사용자를 식별할 수 있는 값이 들어감
  3. Server → Client: HTTP 응답의 Set-Cookie 헤더를 통해 쿠키 전체를 Client에게 보냄
  4. Client: 받은 쿠키를 브라우저의 쿠키 저장소에 자동으로 저장(쿠키의 Key-value)
    .
    이후 요청 시 Client는 저장된 쿠키를 해당 도메인에 요청할때마다 HTTP 요청 헤더에 자동으로 포함해서 서버로 보냄
    Server는 요청에 포함된 쿠키의 값을 확인해서 사용자가 로그인한 상태임을 판별하고 관련 인증/인가를 진행

⇒ Server는 Client로부터 전달된 쿠키의 값을 별도의 Session이나 JWT Token 같은 별도의 메커니즘으로 쿠키 상태를 저장해야함, 해당 메커니즘이 없다면 해당 쿠키가 본인 Server에서 발급된 것인지확인 불가능

하지만 쿠키는 클라이언트 측에서 관리되는 자원이기 때문에 보안적에 있어 취약한 부분이 있습니다.

쿠키의 보안 문제

• 쿠키 값은 클라이언트가 임의로 변경할 수 있으므로, 전송되는 쿠키 값은 위조될 위험이 있습니다.
• 쿠키는 웹 브라우저에 저장되며, 매 요청 시 서버로 전송되기 때문에, 로컬 PC에서 탈취되거나 네트워크 전송 과정에서 가로챌 수 있습니다.
• 만약 쿠키 값이 탈취되면, 해당 쿠키를 이용해 사용자의 인증 상태를 계속 유지할 수 있어 보안상 큰 위협이 됩니다.


Session

세션이란?

웹 어플리케이션에서 한 사용자의 여러 요청을 하나의 연속된 상태로 보고, 그 상태 정보를 일정 시간동안 유지하는 기술

  • 생성
    • 추정 불가능한 임의의 값인 세션 ID 생성
    • 세션 저장소에 세션 ID - 데이터(키-값) 저장
    • 세션 ID로 쿠키 생성하여 HTTP 응답으로 Client에 전달
  • 조회
    • Client가 요청한 세션 ID로 세션 저장소에서 데이터 조회
  • 만료
    • 클라이언트가 요청한 세션 ID로 세션저장소에 보관한 데이터 제거

쿠키의 보안 문제를 해결하기위해 중요한 정보는 서버에만 저장하고 클라이언트와 서버는 그 자체로는 의미가 없으며 추정이 불가능한 임의의 식별자로만 통신을 진행합니다. 이렇게 서버에만 중요한 정보를 보관하고 연결을 유지하는 방식을 세션 방식이라 합니다.

세션 로그인 진행 방식

  1. Client → Server: 로그인 폼으로 Id, pw를 Server에 전달
  2. Server: 로그인 로직을 처리하고 올바른 로그인이면 Session ID를 생성
    • UUID는 식별이 불가능해 Session ID로 사용된다.
    • Java의 UUID를 사용하면 확실한 랜덤값 생성 가능
  3. Server: Server의 세션 저장소에 Session ID와 멤버(로그인한 사용자 정보- id, 권한 등등)를 묶어 보관한다.
    .
    이후 요청 시, Server는 Client에게 JSESSIONID라는 이름으로 Session ID만 쿠키에 담아 전달한다. Client는 쿠키 저장소에 JSESSIONID를 저장한 뒤 이후 요청시 헤더에 포함해 보낸다.
    Server는 쿠키를 통해 전달된 Session ID를 통해 세션 저장소에서 해당 key가 존재하는지 확인하고, 존재한다면 Value 내에 저장된 값들로 인증, 인가를 진행한다.

→ 세션 저장소: 서버 메모리, Redis, DB 등 다양한 방법으로 저장 가능

  • Spring의 HttpSession의 경우 애플리케이션 서버의 메모리에 세션 정보를 저장한다.

→ Session ID와 멤버를 묶어 보관한다

⇒ 쿠키와 달리 세션의 Key 값이 예측 불가능하기 때문에 다른 사용자인 것처럼 보내는 것이 불가능하다

Session의 단점

session은 서버에 연결 정보를 저장하는 것이기 때문에 사용자가 많아질수록 저장해야하는 session이 늘어나 비효율적 처리로 이어집니다.


Spring Security

결국 우리는 API가 실행될 때마다 사용자를 인증해야하는데 Spring Security에서는 그 인증을 구현해 놓았습니다. Spring Security는 인증과 인가를 담당하고 보안에 관련하여 많은 옵션을 제공하는 프레임워크입니다.

Spring Security의 경우 그 양이 굉장히 방대하기 때문에 간단하게 특징과 구조에 대해서만 알아보고 넘어가도록 하겠습니다.

Spring Security 특징과 구조

  • Filter 기반으로 동작하여 MVC와 구분하여 관리, 동작
  • Annotation을 통해 간단하게 설정 가능
  • Spring Security는 기본적으로 세션 & 쿠키 방식으로 인증
  • 인증관리자(Authentication Manager - UsernamePasswordAuthenticationFilter)와 접근 결정 관리자(Access Decision Manager - FilterSecurityInterceptor)를 통해 사용자의 리소스 접근을 관리

Spring Security Filter

Spring에서는 Client가 요청을 보내게 되면 DispatcherServlet이 요청을 처리하게 되는데 DispatcherSevlet이 요청을 받기 전에 다양한 필터들이 있을 수 있습니다.

여기서 필터는 Client와 Server 사이에서 요청과 응답 정보를 전처리, 후처리하는데 목적이 있습니다. Spring Security는 다양한 기능을 가진 필터들을 10개 이상 기본적으로 제공하며 이렇게 제공되는 필터들을 Security Filter Chain 이라고 말합니다.

Spring Security Filter 종류

  • SecurityContextPersistenceFilter: SecurityContextRepository에서 SecurityContext를 가져오거나 저장하는 역할
  • LogoutFilter: 설정된 로그아웃 URL로 오는 요청을 감시하며 해당 유저를 로그아웃 처리
  • (UsernamePassword)AuthenticationFilter: id, pw 사용하는 form 기반 인증, 설정된 로그인 URL로 오는 요청을 감시하며 유저 인증 처리
  • DefaultLoginPageGeneratingFilter: form 기반 또는 OpenId 기반 인증에 사용하는 가상 URL에 대한 요청을 감시하고 로그인 폼 기능을 수행하는데 필요한 HTML 생성
  • BasicAuthenticationFilter: HTTP 기본 인증 헤더를 감시하여 처리
  • RequestCacheAwareFilter: 로그인 성공 이후, 원래 인증 요청에 의해 가로채진 사용자의 원래 요청을 재구성하는데 사용
  • SecurityContextHolderAwareRequestFilter: HttpServletRequest 정보를 감싼다. 다음 필터들에게 부가정보를 제공
  • AnonymousAuthenticationFilter: 이 필터가 호출되는 시점까지 사용자가 인증되지 않았다면 인증토큰에 사용자가 익명 사용자로 나타남
  • SessionManagementFilter: 인증된 주체를 바탕으로 세션 트래킹을 처리해 다닝ㄹ 주체와 관련한 모든 세션들이 트래킹되도록 도움
  • ExceptionTranslationFilter: 보호된 요청을 처리하던 중에 발생할 수 있는 예외의 기본 라우팅과 위임, 전달하는 역할
  • FilterSecurityInterceptor: AccessDecisionManager로 권한 부여 처리를 위임함으로써 접근 제어 결정을 쉽게해줌
  • 로그인 성공시 Spring Security는 Authentication 객체를 만듦
    → 사용자가 누구인지, 어떤 권한을 가지고 있는지 정보가 저장
  • Authentication 내에 UserDetails는 사용자의 구체적인 정보(사용자 이름, 비밀번호, 권한정보)를 저장
  • Authentication 객체를 Spring Security의 Security Session에 저장
    → 사용자가 이후에 다른 요청을 할 때, 이 Session 정보를 기반으로 인증 인가 진행

JWT Token

JWT(Json Web Token)

로그인 이후 Server가 만들어서 사용자에게 넘겨주는 문자열로

해당 문자열은 사용자 정보가 암호화 되어있고, 이 토큰을 이용해서 사용자가 인증됐는지 확인할 수 있습니다.

JWT Token 구조

Header, Payload, Signature로 구성 → xxxxxx.yyyyyy.zzzzzz 로 표현(구분자: ‘ . ‘)

  • Header: 토큰 종류와 해싱 알고리즘 정보가 담김
    • type: 토큰의 타입을 지정 → JWT
    • alg: 해싱 알고리즘 지정. 보통 HMAC, RSA가 사용 → 이 알고리즘이 토큰을 검증할때 사용되는 signature 부분에서 사용
  • Payload: 토큰의 내용물이 인코딩된 부분, 토큰에 담을 정보가 들어있는 부분
    • Claim(담는 정보의 한 조각): JSON 형태의 한 쌍으로 이루어져있다.
    • 토큰에는 여러개의 Claim들을 넣을 수 있다.
  • Signature: 토큰을 인코딩하거나 유효성을 검증할때 사용하는 고유한 암호화 코드
    • Header와 Payload를 각각 BASE64로 인코딩 → 인코딩한 값을 비밀키를 이용해(Header.payload) Header에서 정의한 알고리즘으로 해싱 → 해싱 값을 다시 BASE64로 인코딩하여 생성
    • 즉, secret Key로 사용되는 일련의 문자열

JWT 동작 과정

  1. Client → Server: ID, PW를 Server에게 전달
  2. Server: 인증 성공 시 JWT 토큰 생성
    • Access Token: 유효기간이 짧아 요청마다 인증에 사용
    • Refresh Token: 유효기간이 길어 Access Token이 만료됐을때 새 토큰을 발급받기 위해 사용
  3. Server → Client: 생성한 토큰을 전달
  4. Client: 전달받은 토큰을 로컬 스토리지 혹은 쿠키에 저장
    .
    이후 요청 시, Client는 HTTP 헤더에 Authorization: Bearer {accessToken} 형식으로 토큰을 같이 보냄
    Server는 매 요청마다 토큰의 유효성을 검증, 유효하면 해당 사용자의 요청을 인증/인가하고 문제가 있으면 요청을 거부

→ RefreshToken: 만약 Access Token이 만료되면, 클라이언트는 저장된 Refresh Token을 이용해서 새로운 Access Token을 만들 수 있음

→ Access Token의 유효기간을 짧게 잡아 탈취되더라도 문제가 생기지 않게 빠르게 만료

JWT Token 관리

Access Token은 암호화된 토큰이라 하더라도, 탈취된다면 마치 열쇠처럼 사용되어 로그인이 가능해집니다. 따라서 탈취를 방지하기 위해 토큰을 안전하게 관리하는 것이 매우 중요합니다.

JWT 토큰을 SessionStorage나 localStorage 대신 쿠키에 저장할 경우, 서버에서 쿠키를 저장할 때 HttpOnly와 Secure 옵션을 적용하여 보안을 강화할 수 있습니다.

  • HttpOnly의 경우 자바 스크립트에서 접근할 수 없으므로 XSS 공격에 의한 탈취 위험이 줄어듭니다.
  • Secure 옵션의 경우 Https 접속에서만 쿠키가 전송되도록 하여, 네트워크 상에서 탈취될 위험을 낮춥니다.

이렇게 여러가지 로그인 구현 방식에 대해서 공부해 보았고, 청양고추마켓은 Spring Security 기반으로 인증 인가를 진행하되, 인가의 과정에서 JWT 토큰 방식을 사용할 예정입니다.

Spring Security + JWT Token

0개의 댓글

관련 채용 정보