article thumbnail image
Published 2022. 12. 24. 20:57
반응형

인증과 인가란


인증

인증은 서비스에게 일정 권한을 받을 수 있는 상태를 만드는 것이다.

즉, 로그인이 인증이라고 볼 수 있다.

인가

인가는 인증이 되어야만 한다. 권한이라고 볼 수 있는데 로그인 후 글쓰기, 글수정과 같은 것들이

권한이고 이를 하기 위한것이 인가이다. JWT는 인가에 관련된 부분이다.

세션


요즘은 세션보다 JWT를 많이 쓰는데 간단한 이유는 로그인에 과련해서 알아보도록 하자.

세션을 쓸 경우 아래와 같은 단점이 있다.

  • 메모리에 정보를 갖고 있어야 해서 메모리 낭비가 심하다.
  • 메모리가 휘발성이기 때문에 서버를 끄면, 다 날아가서 재로그인 해야한다.
  • 다중 서버의 경우 세션이 다르면 서버마다 재로그인을 하는 불상사가 발생한다.
    그래서 세션을 다 맞춰줘야 한다. 그래서 캐시 서버, 데이터베이스에 저장해 놓기도 한다.
    데이터베이스는 아무래도 속도 측면에서 손해를 보게 된다. 캐시 서버는 이 서버가
    망가지면 끝이다.

JWT는 어떻게 생겼을까?


jwt는 세션과 달리 서버는 아무런 정보도 갖지 않고, jwt를 만들어 클라이언트에게 응답하고 끝이다.

json을 인코딩한 모습을 하고 있는데 아래와 같은 형식이다.

“.”으로 구분하여 총 세가지 데이터가 base64로 인코딩되어 들어가 있다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

이 세가지를 각각 header, payload, verify signatrue라고 한다.

이를 디코딩해서 보면 아래와 같이 볼 수 있다.

  • header

    • 알고리즘과 토큰 정보

    • alg가 중요한데 verify signature를 만드는데 사용할 서명 값을 만드는데 사용된다.

      {
      "alg": "HS256", // 암호화할 알고리즘
      "typ": "JWT" // JWT로 고정
      }
  • payload

    • 실제 사용할 데이터이며, claim이라고 한다.

    • payload의 사용자 정보는 단순히 base64 인코딩이기 때문에 아무나 디코딩할 수 있다.
      그래서 payload를 조작하여 관리자 권한을 가질수도 있는 등 보안상 문제가 발생한다.

      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
      }
  • verify ssignature

    • 누군가 조작을 하였는지 검증하는 서명 값을 갖는다.
    • header, payload, 서버에 감춰놓은 비밀 값을 넣고 header에서 설정한 암호화 알고리즘으로
      돌리면, 여기 들어갈 서명 값이 생성되게 된다. 즉, 서버에 감춰 놓은 키를 알지 못하면, 복호화를
      할 수가 없어서 해킹을 방지할 수 있다.
    • 즉, 서버는 header, payload, 서버만 아는 키로 암호화를 돌려서 계산된 결과 값이
      서명 값과 일치하는지 확인하여 검증하게 된다. 그래서 조작에 대한 보안은 할 수 있다.
    • 결국 서명 값과 계산된 값이 일치하고, 유효 기간도 지나지 않았다면 인가를 하게 된다.

인증 방식


인증 방식

거의 대부분 Request header의 Authorization에 아래와 같이 인증 프로토콜을 사용한다.

Authorization: [Type] [Credentials]

인증 타입

여러가지가 있지만 몇가지만 알아보도록 하자

  • Basic
    • 사용자 아이디와 암호를 Base64로 인코딩한 값을 토큰으로 사용한다.(RFC 7617)
    • 안전하지 않기 때문에 반드시 HTTPS로 전송되어야 한다.
  • Bearer
    • OAuth 2.0에서 대한 토큰을 사용한다.(RFC 6750)

서버의 비밀 키가 뭘까?


우리가 구글 로그인을 사용하면 누구에게도 노출되면 안되는 client secret이라는 것이 있다.

이걸 비밀키로 활용하는데 이는 서명을 하기 위한 값이다. 즉, 발급한 액세스 토큰이 조작되었는지

확인하기 위한 용도와 토큰을 만들기 위한 키이다. 결국 토큰 자체를 탈취 당하면 답이 없는 것이다.

토큰을 조작하면??

이 토큰 값을 벨로퍼트님이 블리깅하신 곳에서 가져온 토큰이다.

비밀키 값은 secret이다.

이 토큰을 디코딩 해보면 아래와 같이 나온다. payload를 보면 userId, username과 같이 정보가 있다.

그럼 서버에서는 이 정보를 갖고 자동 로그인을 승인하게 된다고 가정해보자.

Invlid Signature라고 뜬 이유는 secret key가 다르기 떄문이다.

이제 제대로 된 secret key를 넣으면 Signature Verified로 바뀌게 된다.

아래는 userId를 조작해서 다른 계정으로 로그인을 시도하기 위한 것이다.

하지만 secret key를 모르기 때문에 서버에서 복호화 시 존재하지 않는 토큰이 되기 때문에

조작해서 해킹하는 것은 불가능하다.

JWT의 취약점


대상을 제어하기 불편하다.

예시로 PC에서 로그인하면, 모바일에서는 로그아웃 되도록하는 것이 불가능하다.

반면, 세션일 경우 기존 세션을 종료하기만 하면 되기 때문에 가능하다.

하지만 JWT는 전혀 서버가 정보를 갖고 있지 않기 때문에 불가능하다.

JWT 탈취

아무리 verify ssignature로 검증을 한다고 해도 결국 토큰 자체를 탈취 당하면 방법이 없다.

그냥 해킹 당하는 것이다. 세션을 종료하는 것과 같이 종료할 수 없기 때문이다.

그래서 토큰 수명을 짧게 가져가는 방식으로 어느정도는 해결할 수 있다.

그 토큰이 access token, refresh token으로 해결하는 방법인데, 세션을 종료하듯이

refresh token을 지우거나하면 되기 때문이다. 그럼에도 access token이 살아있는 동안에는

어쩔 수가 없다.

중요한 정보를 담을 수 없음

조작이 불가한 것이지 디코딩을 누구나 해볼 수 있기 때문에 비밀번호와 같은 값들은 담을 수 없다.

참고 자료


https://velopert.com/2389

https://velog.io/@jkijki12/Spirng-Security-Jwt-로그인-적용하기

https://www.youtube.com/watch?v=1QiOXWEbqYQ

반응형
복사했습니다!