JWT토큰과 Spring Security

서지민·2024년 4월 29일

기초 정리

목록 보기
6/6
post-thumbnail

이번에 캡스톤디자인 하면서 킥보드 어플에 사용하는 로그인 기능으로 SpringSecurity를 처음 사용해보았고 거기에 JWT를 함께 사용했다.

기존에 내가 사용하던 방법은 스프링의 인터셉터기능을 이용하는 방식이었으나, 이번에 만드는 웹서버는 REST API서버이기에 해당 방식이 더 어울릴 것 같아 로그인 로직을 새로 구성하였다.

그래서 이 기능에 대해 설명해보려고 한다.


Spring Security

스프링 진영에서 보안을 위해 사용하는 방법들은 여러가지가 존재한다.

  • 스프링 시큐리티
  • 스프링 인터셉터
  • 스프링 세션
  • 스프링 데이터 보안
  • 스프링 클라우드 시큐리티
  • etc...

이렇게 다양한 방법들이 존재하는데 이번에 알아볼 것은 Spring Security이다.

Spring Security란?

  • Spring Security는 JAVA 기반의 애플리케이션에서 보안 기능을 추가하기 위한 인증 및 접근 제어 프레임워크

  • 주로 웹 애플리케이션의
    인증(Authentication)과 권한 부여(인가)(Authorization)를 관리하는 데 사용

  • Spring Security는 개발자들이 XML이나 어노테이션을 통해 선언적으로 보안 요구사항을 관리할 수 있도록 설계

  • 폼 기반 인증, LDAP, OAuth2와 같은 다양한 인증 메커니즘 지원
    -> 유연성 제공

  • 메서드 수준에서의 세밀한 보안 정책 설정부터, URL기반의 접근 제어까지, 매우 사엣한 보안 정책 적용 가능

  • 스프링 부트와 결합되었을 때 아주 강력하고 빠르고 쉽게 활용 가능

    • 단지 몇 가지 설정 + 어노테이션 추가 -> 보안 강화
  • 기본 설정에선 스프링 시큐리티가 모든 요청에 대한 인증 요구
    -> 개발자는 이를 자유롭게 커스터마이즈 하여 세밀하게 조정 가능

결론

  • 자바 기반의 애플리케이션 보안을 위한 프레임워크
  • 개발자들에게 사용하기 쉽고 유연한 보안 설정 옵션을 제공
  • 안전한 애플리케이션 구축을 가능하게 한다
  • 다양한 보안 요구 사항에 대응할 수 있는 풍부한 기능 보유
  • 애플리케이션의 보안을 한 단계 끌어올리는 데 있어 필수적인 도구

인증 VS 인가

여기서 인증과 인가의 차이점에 대해 제대로 짚어보고 가면 좋을것 같다.

  • 인증

    • 사용자나 시스템의 신원을 확인하는 과정
    • 비밀번호, 생체 인식 정보, OTP등 다양한 방법 사용 가능
    • 인증 과정을 통해 사용자는 자신의 신원을 시스템에 증명
    • 인증은 시스템이 사용자를 알아볼 수 있게 만드는 첫 단계
    • 사용자가 시스템에 접근하기 전에 이루어짐
  • 인가

    • 인증된 사용자가 특정 자원에 접근할 수 있는 권한을 부여하는 과정
    • 이 과정에서는 사용자가 시스템 내에서 수행할 수 있는 작업의 범위 결정
    • ex) Read/Write 권한, 특정 기능 & 서비스 이용 권한
    • 인가는 일반적으로 인증이 성공한 후에 수행된다
    • 사용자의 역할이나 그룹 정책에 따라 결정
  • 차이점

    • 인증: 신원을 증명하는 단계
    • 인가: 그 신원에 권한을 부여하는 과정

보안이 중요한 모든 시스템에서 이 두 과정은 서로 보완적으로 작동

올바른 사용자만이 적절한 자원에 접근하고 작업을 수행할 수 있도록 해준다

JWT

이전에 스터디할 때 잠깐 알아본 적이 있는데, 사실 그때는 그렇게 관심있던 부분이 아니었어서 어쩌면 성의없게 알아본 면이 있다.

그래서 이번에 제대로 알아보자

JWT란?

JWT(Json Web Token)는 웹 표준으로서 두 개체 사이에서 JSON객체를 사용하여 가볍고 자가수용적인 방식으로 정보를 안전하게 전송하기 위한 컴팩트하고 독립적인 방식을 정의한다.

솔직히 말이 좀 어렵다

간단하게 JWT는 말 그대로 웹에서 사용되는 JSON형식의 토큰에 대한 표준 규격으로, JSON객체에 인증에 필요한 정보들을 담은 후 비밀키로 서명한 토큰이다.

이 토큰은 정보를 안전하게 전송할 뿐 아니라, 해당 정보가 변조되지 않았음을 검증할 수 있는 메커니즘도 포함하고 있다.

JWT는 주로 사용자 인증 및 정보 교환에 사용된다.

JWT의 구조

JWT는 세 부분으로 구성된다 헤더(Header)/페이로드(Payload)/서명(Signature)


  1. 헤더: 일반적으로 토큰 유형(JWT)과 사용되는 서명 알고리즘으로 구성
  • 대표적인 서명 알고리즘: RS256(공개키/개인키), HS256(비밀키(대칭키))

  • 예를 들어 그런 다음 이 JSON은 Base64Url로 인코딩 되어 JWT의 첫 번째 부분 구성


  1. 페이로드: 사용자 정보의 한 조각인 클레임(claim)이 들어있다.
  • 클레임: 엔터티 및 추가 데이터에 대한 설명
  • 클레임에는 등록된, 공개, 비공개 클레임의 세 가지 유형 존재
  • 페이로드는 쉽게 복호화가 가능하기에 절대 주요정보를 담아선 안된다
  • 예를 들어 그런 다음 페이로드는 Base64Url 로 인코딩되어 JSON 웹 토큰의 두 번째 부분을 구성

  1. 서명: 헤더와 페이로드의 문자열을 합친 후에, 헤더에서 선언한 알고리즘과 key를 이용해 암호한 값
  • 예를 들어 HMAC SHA256알고리즘 사용하는 경우 다음과 같이 생성
  • 서명은 메시지가 도중에 변경되지 않았는지 확인하는데 사용
  • 참고로 헤더에서 선언한 알고리즘에 따라 KEY는 개인키가 될 수 있고, 비밀키가 될 수 있다.
  • 개인키로 서명
    -> 공개키로 유효성 검사, 개인 키로 서명된 토큰의 경우 JWT의 보낸 사람이 누구인지 확인도 가능
  • 비밀키로 서명
    -> 비밀키를 가지고 있는 사람만이 암호화 복호화, 유효성 검사 가능

  1. 모두 합치기
    출력은 HTML 및 HTTP 환경에서 쉽게 전달할 수 있는 점으로 구분된 3개의 Base64-URL 문자열이며, XML 기반 표준과 비교할 때 더 간결하다.
  • 이전의 헤더와 페이로드가 인코딩 되어있고, 비밀키로 서명된 JWT의 모습
  • https://jwt.io/#debugger-io 여기서 직접 JWT를 디코딩, 확인 및 생성해 볼 수 있다

JWT의 사용이유

그러면 왜 JWT를 사용할까?

이전에 공부했던 내용 중 HTTP에 대한 내용을 보면
HTTP의 특성 중 connectionless와 stateless가 있다.
즉 HTTP는 연결을 유지하지 않으며, 상태 또한 유지하지 않는다는 것이다.

그래서 이것이 JWT와 무슨 관련이 있느냐?
JWT를 결국 "로그인"이라는 과정을 위해 사용하는데, 이 "로그인"이라는 과정은 서버-클라이언트간 데이터를 주고 받는 통신 방법이 필요하고, 그 통신 방법이 HTTP이다.

이러한 특성들 때문에 우리가 "로그인"을 구현하는데 많은 어려움을 겪는다.

자신이 누구인지 계속해서 인증해야 하는 것
매번 서버에 사용자가 누구인지 인증을 하는 과정은 번거롭고 귀찮을 뿐만 아니라
매번 요청을 보내야 하기 때문에 우리의 웹페이지가 느려지는 원인이 된다.

위의 원인과 이유로 우리는
사용자가 누구인지 계속해서 인증을 하는 방법 대신
다른 로그인 정보를 유지시킬 방법이 필요했다.

그리고 그 방법 중 하나가 바로 JWT이다.

다른 방법으로 세션도 있으나 이 둘의 비교는 추후에 알아보도록 하자

JWT의 사용 방법

2가지의 방법이 존재한다

  • Only Access Token(액세스 토큰만 사용)

  • With Refresh Token(액세스 토큰 + 리프레시 토큰)
    위의 방식으로 했을 때 문제점은 Access Token을 탈취 당했을 때이다.
    유효기간이 긴 토큰이라면 그 기간동안 탈취한 사람은 계속해서 사용할 수 있다.
    그래서 또 유효기간을 줄이자면 사용자가 로그인을 여러 번해야 하는 번거로움이 있다.
    그래서 나온것이 Refresh Toekn이다

    Refresh Token역시 Access Token과 같은 JWT인데,
    로그인을 했을 때 서버에서 이 둘을 동시에 보내준다
    단, 둘의 유효기간을 다르게 해서 보낸다.

    Refresh Token을 한 달, Access Toekn을 하루로 잡았다면
    Access Token의 기간이 다 되어도 Refresh Token의 기간이 남아있기 때문에
    사용자는 로그인 없이 다시 Access Token을 발급 받을 수 있다.

내가 이번 캡스톤 디자인에서 사용한 방식은 첫 번째 방식이다.

JWT 장단점

장점

  • 세션 방식과 다르게 별도의 인증 저장소가 필요 없어서 서버와의 커뮤니케이션을 최소한으로 할 수 있다.
  • 트래픽에 대한 부담이 적다.
  • 세션과 다르게 독립적인 느낌의 JWT를 활용한다는 것.

단점

  • JWT의 크기가 커질수록 거의 모든 요청에 대해 전송되므로 데이터 트래픽 크기에 영향을 미칠 수 있다.
  • 토큰은 클라이언트에 저장되기 때문에 DB에서 사용자 정보를 수정하더라도 토큰에 직접 적용할 수 없다.

SpringSecurity와 JWT

Spring Security와 JWT를 결합하는 것은 인증 및 인가 과정을 관리하기 위한 매우 효과적인 방법이다.

SpringSecurity는 강력한 보안 프레임워크 제공

  • JWT는 상태를 유지하지 않는 인증 시스템 지원

이 결합을 통해, 개발자들은 안전하고 확장 가능한 인증 시스템 손쉽게 구축

통합 방법

  1. 우선 의존성부터 각각 추가

  2. Spring Security 설정

  • Spring Security를 사용해서 인증 메커니즘을 설정한다

  • 스프링 부트 3.1.X ~ (스프링 6.1.X ~ )의 경우

    public class SpringSecurityConfig {
    
      @Bean
      public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
          http
              .authorizeHttpRequests((auth) -> auth
                    .requestMatchers("/login", "/join").permitAll()
                    .anyRequest().authenticated()
          );
    
          return http.build();
      }
    }
    
  • 그 외의 버전의 경우 버전 별 SpringSecurity 참고

  1. JWT필터 생성
  • JWT를 생성하고 검증하는 필터를 생성
  • 이 필터는 사용자가 로그인 할 때 JWT를 생성
  • 이후 모든 요청에서 HTTP헤더에 포함된 JWT를 검증
  1. 인증 및 인가 처리
  • 사용자가 로그인하면, 사용자의 인증 정보 바탕으로 JWT생성 & 반환
  • 이후 사용자는 이 JWT를 HTTP헤더에 포함시켜 서버로 요청
  • 서버는 JWT필터를 통해 토큰의 유효성 검증

결론

Spring Security와 JWT를 결합함으로써, 개발자들은 강력하고 유연한 인증 시스템을 구축할 수 있으며, 애플리케이션의 보안성을 크게 향상시킬 수 있다.

이번 프로젝트에선 단방향으로 Access Token만 사용 하는 방식으로 구현하였는데, 다음에는 Refresh토큰을 같이 사용하는 방식으로 프로젝트를 하나 제작하려고 한다

이 두 가지 모두 처음 사용하는 것이라 많이 어색하고 어려움이 있었지만, 차근차근 도입해가면서 어느정도 이해가 된 것 같다.


참고

https://velog.io/@junghyeonsu/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95

https://velog.io/@chuu1019/%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90-JWTJson-Web-Token

profile
효율 이전에 노력의 축적이 필요하다

0개의 댓글