[normaltic 취업반 5기] 2023-11-08 3주차 과제 : 추가 과제

2023. 11. 11. 10:49normaltic 취업반 5기/과제

 

JWT (JSON Web Token)

 

JWT는 쿠키, 세션에 이은 인증 프로토콜 중 하나이다. 다만 쿠키나 세션 같이 어느 한 곳에 사용자 정보를 저장하는 방식이 아니라 토큰에 사용자 정보를 저장하여 인증하는 방식이다. 또한 토큰이 탈취되어 데이터가 위변조 된 상태로 요청되어도 위변조 검사가 가능하기 때문에 로그인 유지 및 식별에 많이 사용된다.

 

JWT의 구조

JWT의 구조와 각 요소들

 

JWT는 '.'을 구분자로, base64로 Header와 Payload를 인코딩한 값과 인코딩하지 않은 두 값에 비밀 키를 합쳐서 암호화한 값인 Signature로 구성되어 있다. 그럼 Header와 Payload, 그리고 Signature에 대해 알아보자.

Header

Header

 

Header는 JSON 객체로 이루어져 있으며 암호화 알고리즘과 토큰의 타입에 대한 정보가 담겨있다.

Payload

Payload

 

Payload는 JSON 객체로 이루어져 있으며 Claim이라는 사용자에 대한 정보 혹은 토큰에 대한 정보가 Key-Value 형태로 정보가 담겨있다. Claim은 토큰에서 정보의 조각을 의미하며 개발자에 따라 구성되는 Claim이 다르다.

 

JWT에서 Claim에 대한 표준 스펙이 존재한다. Key의 이름은 3글자로 이루어져 있으며 Claim에 담겨야할 정보는 사용자 정보 및 토큰 정보에 대한 표현을 압축한 정보에 대한 예시가 정의되어 있다.

 

  • iss(Issuer) : 토큰 발급자 혹은 발급처
  • sub(Subject) : 인증 주체, 토큰 제목
  • aud(Audience) : 토큰 대상자, 클라이언트
  • exp(Expiration Time) : 토큰 만료 시간
  • nbf(Not Before) : 토큰 활성 날짜
  • iat(Issued At) : 토큰 발급 시간
  • alg(Algorithm) : 암호화 알고리즘
  • typ(Type) : 토큰 유형

 

위 표준 스펙 말고도 추가해야만 하는 정보가 있으면 임의로 추가가 가능하다. 또한 표준 스펙을 모두 포함하지 않아도 되기 때문에 개발자의 취향에 따라 Payload에 저장되는 정보들이 다를 수 있다.

Signature

Signature

 

Signature는 JSON 형식의 Header와 Payload의 값을 Header에서 명시한 암호화 알고리즘으로 암호화한 값이다. 그리고 암호화된 Signature를 복호화하기 위해서는 서버 측이 가지고 있는 비밀키(예시에서는 your-256-bit-secret)로만 가능하다. 이를 통해 공격자가 토큰을 탈취하고 Header와 Payload의 값을 위변조 후 요청하여도 서버 측에서 Signature를 복호화하여 Header와 Payload의 값을 비교하여 값의 일치여부를 판단할 수 있다. 이때 일치하지 않으면 인증이 거부가 되기 때문에 높은 보안성을 가진다.

 

JWT의 특징

  • 쿠키와 세션은 인증 정보를 보관할 저장소가 필요하지만 JWT는 토큰이 곧 인증 정보이기 때문에 세션 저장소 같은 저장소가 따로 필요하지 않다.
  • Signature를 암호화했기 때문에 토큰 탈취 후 서버에 요청 시 Signature 복호화를 통한 위변조 검사가 가능하여 높은 보안성을 가진다.
  • Header와 Payload는 base64로 인코딩한 것이기 때문에 사용자 인증에 필요한 내용만 입력하는 것이 좋으며 중요한 정보는 Payload에 포함하는 대신 서버 측에서 DB를 통해 조회하는 편이 안전하다.

 

PHP를 이용한 JWT 로그인 기능 구현

 

기능 구현에 사용된 페이지

  • test_jwt.php : jwt 관련 함수가 입력되어 있는 페이지
  • test_login.php : 로그인 화면을 보여주는 페이지
  • test_login_proc.php : 로그인 기능 처리 페이지
  • test_my.php : 로그인에 성공한 후 토큰 검증에 대한 결과를 보여주는 페이지

test_jwt.php

 

test_jwt.php 파일에는 jwt에 관련된 두 함수가 입력되어 있다.

 

 

함수 hashing의 기능은 파라미터로 들어온 배열 데이터를 jwt 형태로 만들어주는 역할을 한다.

  • $header : 암호화 알고리즘과 토큰 타입에 대한 정보를 가진 연관배열을 JSON 형태로 인코딩한 값을 저장한 변수
  • $payload : 파라미터로 들어온 연관배열을 JSON 형태로 인코딩한 값을 저장한 변수, 보통 식별 및 인증에 성공한 사용자의 정보를 저장한다.
  • $signature : "$header+$payload+비밀키"로 이루어진 문자열을 $header 변수에서 명시한 암호화 알고리즘으로 암호화 한 값을 저장한다.
  • $header와 $payload와 $signature를 '.'을 구분자로 쓴 문자열("$header.$payload.$signature")을 base64로 인코딩한 값을 반환한다.

 

 

함수 dehashing의 기능은 파라미터로 들어온 토큰값을 검증하는 역할을 한다.

  • $part : explode 함수를 사용하여 $token을 base64로 디코딩 후 '.'을 구분자로 문자열을 나누어 배열로 저장한다.
  • $request_header : 검증 전 헤더 값을 저장한다.
  • $request_payload : 검증 전 페이로드 값을 저장한다.
  • $signature : 시그니쳐를 저장한다.
  • 토큰 생성 과정에서 시그니쳐 변수를 저장한 방법으로 $request_header와 $request_payload를 이용하여 만들어진 값과 $signature값의 일치여부를 확인한다.
  • 값이 일치하지 않을 경우 오류 팝업창을 보여주고 0을 반환한다.
  • 값이 일치할 경우 $request_payload를 JSON 형태에서 디코딩한 배열값을 반환한다.

 

test_login.php 

 

 

 

로그인에 필요한 기본적인 요소만 입력되어 있다. ID와 Password를 입력 후 로그인 버튼을 누르게 되면 test_login_proc.php 페이지로 이동하게 된다.

 

test_login_proc.php

 

 

기존 로그인 페이지와 처리 과정은 똑같은 흐름으로 이어지나 세션 유지에 필요한 jwt를 생성하고 발급하는 과정이 추가되었다.

 

 

  • jwt 관련 함수를 사용하기 위해 test_jwt.php 파일을 불러온다.

 

 

  • 식별 및 인증 과정이 성공적으로 완료되면 페이로드에 저장할 정보를 연관배열 형태로 hashing 함수 파라미터에 입력한다.
  • hashing 함수로 반환된 값을 $login 변수에 저장한다.
  • 쿠키를 발급하기 위해 setcookie 함수를 사용한다. 쿠키명이 "Access_Token"이고 쿠키값은 $login 변수, 그리고 쿠키의 만료 시간은 3600초 즉, 1시간으로 설정하여 쿠키를 발급한다.
  • 이제 클라이언트는 발급된 쿠키를 요청할 때마다 동봉하여 전달한다. 그럼 서버 측에서는 사용자 정보가 필요한 경우 쿠키를 검증하여 사용자인지 검증하는 과정을 거친다.

 

test_my.php

 

클라이언트 측에서 요청 시 쿠키의 검증 과정이 요구되는 페이지이다.

 

 

  • jwt 관련 함수를 사용하기 위해 'test_jwt.php' 파일을 불러온다.
  • 클라이언트가 요청했을 때 같이 보내온 쿠키명이 "Access_Token"인 쿠키의 값을 $request_token 변수에 저장한다.
  • dehashing 함수에 $request_token 변수를 파라미터로 입력하여 검증 과정을 거친다. 검증이 성공적으로 완료되면 $payload에 저장되는 값은 사용자 정보가 될 것이고 검증에 실패하면 0이 저장될 것이다.
  • $id 변수에 $payload['user_id'] 값을 대입하여 사용자 정보를 저장한다.

 

 

  • jwt 인증을 성공하여 사용자에 대한 정보를 DB에 조회한다.
  • 조회된 내용을 화면에 표시한다.

 

출력 화면

 

쿠키 확인 방법

발급된 쿠키는 크롬 기준 오른쪽 상단에 3개 점 클릭 => 도구 더보기 => 개발자 도구 => 네트워크 => 페이지 이름을 클릭하면 헤더값들을 확인할 수 있다.

 

 

작동 및 쿠키 확인