JWT

Shaun·2022년 3월 16일
1

Spring Security

목록 보기
19/19

JWT 에 대해 배워보기전에 보안에 대해 간략히 알아보자

보안에는 크게 두가지의 고질적인 문제가 있다.

-보안의 고질적적 문제-
1. 열쇠 전달 문제 ( 암호화시켜서 열쇠를 보내면 좋은데 열쇠도 도둑맞을수 있다)
2. 누구로 부터 받았는가( 중간에 가로채거나 , 문서를 위조하거나)

해결책

RSA

-RSA 에는 개인키, 공개키 라는 개념이 있다. 공개키는 누구나 얻을수있고 개인키는 개인만 가지는 키다.

  • 공개키로 잠그면 개인키로 열수있다. 개인키로 잠그면 공개키로 열수있다.
  • 개인키로 잠그고 다른 사람이 공개키로 열떄 누가 보냈는지 문제 해결
  • 공개키로 잠그면 개인키로만 열리기 때문에 열쇠전달문제 해결

세션

  • 클라이언트가 id,password로 로그인을 시도해 인증이 성공하면 서버는 권한 등 기본적인 데이터를 서버에 저장하고 세션id를 쿠키에 담아 클라이언트에게 돌려준다.

  • 다음에 클라이언트가 리퀘스트를 쿠키의 세션아이디와 함께 보낸다.

  • 서버에서는 해당 세션아이디가 서버에 있는지 확인후 있으면 그 데이터 안에있는 권한에 해당하는 자료를 보여준다.

  • 서버의 트래픽이 많아지면 서버가 늘어나고 늘어남에따라 세션id가 변동되고 많은 문제점이 있다.

=> JWS 를 사용하자!

JasonWebToken (JWS) 는 왜 사용 할까??

장점

  • 기존 SpringSecurity를 통해 구현하는 방법보다 훨씬 간단하다!

  • 서버에서는 신경을 쓸필요가 없다. 모든 정보는 클라이언트에게 주어진다.

단점

  • 보통 동시 로그인 할떄 보통 서버에서 세션 id 하나를 만료시키면되지만 (세션id가 서버에 저장되잇으니까) jwt는 클라이언트가 관리하므로 서버에 아무것도 없다. 그래서 모든토큰을 초기화시키는거 말고는 방법이 없다. or jwt만들떄 만료기간을 작성

  • 또는 jwt토큰이 유출 됐으면 어찌 할 방법이 없다. (가장 큰 단점) 그래서 jwt에 암호화, 핸드폰 잠금화면처럼 2차 암호화를 한다.

JWT

  • JWT는 크게 세부분으로 나누어 진다. 헤더/페이로드/시그니처

    헤더:알고리즘 , 토큰타입
    페이로드:데이타, subject, name , issuedat(언제토큰이 발행됫는지) 내용을 더추가할수도있다.// 네트워크의 데이터가 올라가기 때문에 최소한의 데이터만 적는게 좋다.
    시그니처: 시크릿 키를 적으면 그 헤더값과 페이로드가 그 시크릿키로 묶인다고 보면 됀다. / =저장한 상태 이름으로 해시값을 받아온다

JWT - HMAC방식

  • 서버가 자기만 아는 SecretKey + Payload +head 을 조합하고 HS256으로 암호화

  • 각각의 header / payload / signature 각각을 Base64로 인코딩함 = 디코딩하면 바로 정보 튀어나옴 = 암호화목적이 아닌 서명이 목적이다

HS256 = HMAC방식(시크릿키를 포함한 암호화 방식)으로 + SHA26(해시)으로 암호화

JWT-RSA방식

  • Secretkey가 필요없고. Header + payload 를 서버 개인키로 잠궈서 시그니처 만든다.

  • 검증을 할떄는 공개키로 확인한다

JWT-flow

  1. 클라가 아이디와 비밀번호 입력해 인증을 성공하면 서버에 보내면 서버는 토큰을 준다. 이 토큰값에 우리가 원하는 데이터를 넣을수 있다. 이 토큰에는 사용자의 아이디,비밀번호, 토큰종료시간 등등 데이터가 암호화 되어서 들어있다.

  2. 클라가 헤더 Authorization 객체 key-value 값에 토큰값을 넣어 보내면 서버는 key값을 넣어 value(토큰값) 을 꺼내 인증을 시도한다.(이동시)

  3. 서버에서의 인증은 토큰을 파싱한다(토큰을 우리가 읽을수 있는형태) 그뒤에 토큰안에 있는 데이터를 꺼낸다.

  4. 그 데이터로 DB에서 계정정보를 가져온뒤에 UserDetails 타입으로 만든뒤 UsernamePasswordAuthenticationToken 생성(계정,비번,권한) => Authentication가져오기 -> SecurityContextHolder에 넣기 ->세션에 저장 =>인증성공

실습

  • userName으로 DB에 해당 계정이 있나 확인하는 userDetailService loadUserByUserName() 구현 부분이다. 계정을 찾은뒤 userDetails 타입을 반환을 한다.

  • 클라이언트가 JSON 형식으로 보낸 id와 passWord를 ObjectMapper로 받은뒤 해당 userName으로 DB에서 계정을 찾는다.

  • 계정을 찾은뒤 그 계정,비밀번호,권한을 userNamePasswordAuthenticationToken에 담아서 AuthenticationManager 에게 인증 요청을 한다.

  • AuthenticationManager 은 AuthenticationProvider에게 인증을 위임하고 authenticate() 메서드로 실질적 인증을 시도한다.

  • 인증이 성공하면 그 결과를 Authentication 객체에 담아서 반환한다.

토큰만들기(인증성공 이후)

  • 인증이 성공한 이후의 과정 메서드다

  • 인증이 성공 했으니 서버에서는 클라이언트에게 토큰생성시간,토큰종료시간, 인증계정의 정보등 데이터를 JWT토큰으로 만든뒤 클라에게 다시 보낸다.

토큰 사용하기(파싱)

  • 인증에 성공한 계정은 토큰값을 가지고 있으며 권한이 필요로하는 자원에 접근시 서버에서는 토큰값을 검사해 권한을 확인한다.

  • BasiceAuthenticationFilter 를 상속 해준다. 권한이나 인증이 필요하면 이 필터를 타게 되있다.

  • 클라이언트는 헤더안의 Authorization 객체안에 토큰값을 넣어 서버로 보낸다.

  • 그러면 서버는 그 토큰 값을 꺼내 ->시크릿키로 JWT파일을 검사한다(변경여부 확인)

  • 서버에서는 리퀘스트로 온 헤더와 페이로드 시크릿키를 결합해 시그니처를 만들어본뒤 그값이 JWT생성시 만들었던 시그니처와 일치하면 변경여부를 통과시킨다.

  • 검사가 통과되면 JWT에 담긴 데이터로 UserDetails타입의 user를 만든뒤 Authentication객체에 담고 이것을 SecurityContextHoler ->Session 에 저장하면 인증이 완료된다.

  • 이코드에서는 JWT를 만들때 userName 데이터를 넣어줘서 이 데이터를 가지고 계정을 검색한뒤 userDetails 타입으로 만들어 주고 인증을 했다.

JJWT라는 라이브러리를 이용해서도 JWT토큰을 많이 사용한다.이 라이브러리에 대한 설명은 링크만 남긴다.
JJWT링크

profile
호주쉐프에서 개발자까지..

0개의 댓글