[T.I.L] 인증(Authentication)과 인가(Authorization)

재운·2021년 4월 6일
0
post-thumbnail

인증(Authentication)

유저의 identification을 확인하는 절차
👉 흔히 우리가 로그인(log-in)하는 절차가 '인증'이다.

<로그인 절차>

  1. 유저 ID와 PW 생성
  2. 유저 PW 암호화해서 DB에 저장 --> 여기까지 회원가입
  3. 유저 로그인 : ID, PW 입력
  4. 유저가 입력한 PW 암호화하여 DB에 저장된 암호화된 PW와 비교하여
    일치하면 로그인 성공 --> 여기까지 로그인('인증')
  5. 로그인 성공하면 access token을 클라이언트에 전송
  6. 이후 유저는 request시 access token을 첨부하여 전송하여 매번 로그인할 필요가 없도록 한다.

<비밀번호 암호화>

  • 비밀번호는 DB에 그대로 저장되지 않고 암호화돼서 저장된다.
  • 비밀번호 암호화에서는 단방향 해쉬 함수(one-way hash function)가 일반적으로 쓰인다.

해쉬 함수란?
임의의 길이를 갖는 메시지를 입력받아 고정된 길이의 해시값을 출력하는 함수.
같은 입력에 대해서는 항상 같은 출력이 나오게 된다. 이러한 해시함수를 사용하는 목적은 메시지의 오류나 변조를 탐지할 수 있는 무결성을 제공하기 위해 사용된다.

단방향 해쉬 함수에도 약점이 있다.
'Rainbow table' 이라고 해쉬값들을 미리 저장해놓은 테이블을 이용할 경우에 패스워드가 복잡하지 않을 경우 긴 시간을 들이지 않고 비밀번호를 알 수 있다.

이 약점을 보안하기 위해 두가지 방법이 사용된다.

  • salting: 비밀번호 의외에도 랜덤 문자열을 추가하여 해시값을 계산하는 방법

  • key streching: 단방향 해쉬값을 여러번 계산하는 방법

👉 우리가 회원가입을 하면 입력한 비밀번호가 해쉬되어 DB에 저장되고,
우리가 로그인을 할때 비밀번호를 입력하면 해당되는 아이디의 비밀번호 해쉬값과 우리가 입력한 데이터의 해쉬값을 비교해 사용자 인증을 진행한다.

인가(Authorization)

'인가'는 유저가 요청하는 request를 실행할 수 있는 권한이 있는 유저인지 확인하는 절차이다.

<'인가' 절차>

  1. 로그인을 진행하면 백엔드 서버에서 클라이언트에게 'Access Token'을 생성하여 Header에 첨부하여 프론트에게 보내준다.
  2. 프론트에서 local storage에 토큰을 저장하고 있다가, 유저가 request를 보낼때 토큰을 header에 첨부하여 서버에게 보낸다.
  3. 서버는 토큰을 복호화(decode)하여 user id를 확인하고 접근 권한을 확인하여, 권한을 가지고 있으면 해당 요청을 처리한다.

여기서 '토큰'은 무엇이고 왜 사용하는 것일까?

"서버측에서는 유저의 세션을 유지 할 필요가 없다. 즉 유저가 로그인되어있는지 안되어있는지 신경 쓸 필요가 없고, 유저가 요청을 했을때 토큰만 확인하면 되니, 세션 관리가 필요 없어서 서버 자원을 많이 아낄 수 있다."

'세션'에 대해서는 나중에 포스팅을 한번 해야겠다.(세션,쿠키...)

본론만 얘기하면 '유저의 인증상태 관리가 편하다' 는 말이다.

대표적인 토큰으로 JWT(Json Web Token)이 있고, JWT는 웹표준 (RFC 7519) 으로서 두 개체에서 JSON 객체를 사용하여 가볍고, 정보를 안전성 있게 전달해준다고 한다.

JWT

<JWT의 구조>

1) Header

헤더는 두가지 정보를 가지고 있다.

typ : 토큰의 타입을 지정(예:JWT)
alg : 해싱 알고리즘을 지정(예:HS256). 알고리즘은, 토큰을 검증 할 때 사용되는 'signature' 부분에서 사용된다.

{
  "typ": "JWT",
  "alg": "HS256"
}

이러한 형식으로 되어 있고 이를 base64로 인코딩하면,
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" 와 같이 나타난다.

2) Payload

토큰에 담을 정보가 들어있다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(claim) 이라고 부르고, 이는 {name : value} 의 한 쌍으로 이뤄져있다. 토큰에는 여러개의 클레임 들을 넣을 수 있다.

클레임의 종류에는 3가지가 있다.

  • 공개 클레임(public claim)
  • 비공개 클레임(private claim)
  • 등록된 클레임(registered claim)

등록된 클레임(registered claim)

등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임들이다. 등록된 클레임의 사용은 선택적이다.

  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야한다.
  • nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념이다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
  • iat: 토큰이 발급된 시간, 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있다.
  • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용하다.

공개 클레임(public claim)

공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용한다.

EX)

{
"https://velog.io/@adsf25":True
}

비공개 클레임(private claim)

비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
유저 정보같은 경우 비공개 클레임으로 담는다.

{
    "username": "adsf25"
}

클레임 사용 예시

{
"iss": "velog.io", -->등록된 클레임
"exp": "1485270000000", -->등록된 클레임
"https://velog.io/@adsf25": true, --> 공개 클레임
"username": "adsf25" --> 비공개 클레임
}

위와 같은 정보들이 인코딩되어 토큰에 저장된다.

3) Signature

서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다. 서명(Signature)은 위에서 만든 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩하고, 인코딩한 값을 비밀 키를 이용해 헤더(Header)에서 정의한 알고리즘으로 해싱을 하고, 이 값을 다시 BASE64로 인코딩하여 생성한다.
여기서, 비밀키는 공개되지 않는곳(.gitignore)과 같은곳에 저장하여 사용한다.

<JWT 토큰 예시>

추가) JWT 의 단점

  • 토큰 자체에 정보를 담고 있으므로 양날의 검이 될 수 있다.

  • 토큰 길이: 토큰의 페이로드(Payload)에 3종류의 클레임을 저장하기 때문에, 정보가 많아질수록 토큰의 길이가 늘어나 네트워크에 부하를 줄 수 있다.

  • Payload 인코딩: 페이로드(Payload) 자체는 암호화 된 것이 아니라, BASE64로 인코딩 된 것이다. 중간에 Payload를 탈취하여 디코딩하면 데이터를 볼 수 있으므로, JWE로 암호화하거나 Payload에 중요 데이터를 넣지 않아야 한다.

  • Stateless: JWT는 상태를 저장하지 않기 때문에 한번 만들어지면 제어가 불가능하다. 즉, 토큰을 임의로 삭제하는 것이 불가능하므로 토큰 만료 시간을 꼭 넣어주어야 한다.

  • Tore Token: 토큰은 클라이언트 측에서 관리해야 하기 때문에, 토큰을 저장해야 한다.

profile
Life is memory

0개의 댓글