[WEB #13] 인증과 인가(개인정보 관리)

Kayoung Kim·2021년 11월 1일
1

Web Development

목록 보기
15/18
post-thumbnail

인증(Authentication)

  • 유저의 identification을 확인하는 절차 (아이디, 비밀번호 확인)
  • 우리 서비스를 누가, 어떻게 사용하는지 추적하기 위해 사용한다.
  • 인증에는 아이디, 이메일 주소, 비밀번호* 등이 필요하다.

비밀번호 관리

  • 비밀번호는 개인정보보호법에 따라 '암호화'해서 관리해주어야 한다. (법규상 강제)
  • 비밀번호는 Database에 저장 시 개인정보를 해싱(난독화)하여 복원할 수 없도록 한다.
  • 통신 시 개인 정보를 주고받을 때 SSL을 적용하여 암호화한다. (HTTPS 프로토콜)

암호화 방법

단방향 해쉬 함수(one-way hash fuction)

  • 해시(hash)함수는 자료구조에서 빠른 자료와 검색, 데이터의 위변조 체크를 위해 쓰이며, 복원이 불가능해 암호학적 용도로 사용한다. (예: MD5, SHA-1, SHA-256)
  • 단방향 해시 함수는 원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest)를 생성한다. 원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 암호화된 메시지로는 원본 메시지를 구할 수 없어서 단방향성(one-way) 이라고 한다.
  • 예를 들어, "test password"를 hash256이라는 해쉬 함수를 사용하면 0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e 값이 나온다.
  • 만일 "test password2"를 hash256 해쉬 함수를 사용하면 d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb 값이 나온다. 실제 비밀번호는 비슷하지만 해쉬 함수 값은 완전히 틀린것을 볼 수 있다. 이러한 효과를 avalance라고 하는데 비밀번호 해쉬 값을 해킹을 어렵게 만드는 하나의 요소이다.
  • 결과만 보고 식별이 불가능하기 때문에 완벽해보이지만, 같은 알고리즘으로 해싱하면 같은 결과가 도출되기 때문에 위험할 수 있다. (Rainbow Table attack: 가능한 경우의 수를 모두 해시값으로 만들어 판매하는 서비스)
    => salting, Key Streching 개발됨

Salting & KeyStretching (소금치고 늘리기!)

  • 솔팅(Salting)은 실제 비밀번호 이외에 추가적으로 랜덤 데이터를 더해서 해시값을 계산하는 방법이다.
  • 입력한 비밀번호와 임의로 생성한 문자열을 합쳐서 해싱, 이 해싱값 결과를 저장한다.
  • 비교를 위해 해시값과 솔트값을 같이 저장해야 한다.
  • 키 스트레칭(Key Stretching)은 단방향 해쉬값을 계산한 후 그 해시값을 또 해쉬하는 반복 작업으로, 해커가 패스워드 무작위 대입을 통해 해시값을 계산하는데 필요한 시간을 대폭 늘려 원본 값을 유추하기 어렵게 만든다.

bcrypt

  • Salting & Key Streching 개념들을 적용해주는 대표적 라이브러리
  • 처음부터 비밀번호를 단방향 암호화하기 위해 만들어진 해쉬 함수로 hash 결과값에 솔트값, 해시값 및 반복횟수를 같이 보관하기 때문에 DB 설계가 편리하다는 장점이 있다.

로그인 절차

  1. 유저 아이디와 비밀번호 생성
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json

{
    "username": "joe",
    "password": "pass"
}
  1. 유저 비밀번호 암호화 -> DB에 저장.
  2. 유저 로그인 -> 아이디와 비밀번호 입력
  3. 유저가 입력한 비밀번호 암호화 -> 암호화되서 DB에 저정된 유저 비밀번호와 비교
  4. 일치하면 로그인 성공
  5. 로그인에 성공하면 access token을 클라이언트에게 전달
// 유저 로그인
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json

{
    "username": "joe",
    "password": "pass"
}
// access token
HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
  1. 서버에서 access token을 복호화해 유저 정보를 얻는다. 유저는 로그인 성공후 다음부터는 access token을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.
    (HTTP를 알고 주소 쓰기 참조)
{
  user_id = 1
}

JSON Web Token(JWT)

  • access token을 생성하는 널리 사용되는 기술중 하나로, 유저 정보를 담은 JSON 데이터를 암호화해서 클라이언트와 서버간에 주고 받는다.

JWT 구성

  • 헤더(header): 토큰 타입의 해시 알고리즘 정보로 BASE64 방식으로 인코딩 되어 JWT의 가장 첫부분에 기록됨 (암호화 x) 예: {"alg":"HS256", "typ":"JWT"}
  • 내용(payload): 내용에는 exp와 같이 만료시간을 나타내는 공개 클레임, 클라이언트와 서버간 협의하에 사용하는 비공개 클레임. 두가지 요소를 조합하여 작성한 뒤 BASE64 인코딩해 두번째 요소로 위치 예: {"user-id": 1, "exp":1539517391}
  • 서명(signature): JWT가 원본 그대로라는 것을 확인.
    BASE64URL 인코드된 header와 payload 그리고 JWT secret(별도 생성)을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송 (복호화 가능)
  • 프론트엔드가 JWT -> 백엔드 API 서버 전송 -> JWT 서명부분 복호화하여 서버 생성 유무 확인
    => header와 payload는 암호화가 아닌 BASE64 인코딩한 것이므로 누구나 원본을 볼 수 있으니 개인정보를 담아선 안된다.

Access token을 사용하는 이유

  • 무거운 bcrypt call을 받지 않고, 간단한 해쉬 만으로 퍼포먼스를 낼 수 있다.
  • Client-side storage방식
    쿠키와 같이 실제 ID와 패스워드가 저장되지 않고, 다른 사이트에서 재사용할 수 없기 때문에 안전하다.

인가(Authorization)

  • 유저가 요청하는 request를 실행할 수 있는 권한이 있는 유저인가를 확인하는 절차다.
  • 예를 들어, 해당 유저는 고객 정보를 볼 수 있는 있지만 수정할 수는 없다
  • Authroization도 JWT를 통해서 구현 될 수 있다.
    • access token을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)도 확인 할 수 있다.

인가 절차

  1. Authentication 절차를 통해 access token을 생성한다. access token에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다 (예: user id).
  2. 유저가 request를 보낼때 access token을 첨부해서 보낸다.
  3. 서버에서는 유저가 보낸 access token을 복호화 한다.
  4. 복호화된 데이터를 통해 user id를 얻는다.
  5. user id를 사용해서 database에서 해당 유저의 권한(permission)을 확인하다.
  6. 유저가 충분한 권한을 가지고 있으면 해당 요청을 처리한다.
  7. 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.

0개의 댓글