Session: 인증/인가

Magit·2020년 4월 15일
0

Session

목록 보기
5/6

인증과 인가

  • 인증과 인가는 API에서 가장 자주 구현되는 기능중 하나이다.
  • Private한 API는 물론이고 Public한 API도 기본적인 인증과 인가를 요구한다.

인증(Authentication)은 무엇이고 왜 하는 걸까?

  • 인증은 회원가입과 로그인을 말한다. 쉽게 말해 유저의 아이디와 비번을 확인하는 절차이다. 즉, 인증을 하기 위해서는 먼저 유저의 아이디와 비번을 생성할 수 있는 기능도 필요하다.
  • 인증은 왜 필요한가?
    • 서비스를 누가 쓰고 어떻게 사용하는지 추적이 가능하도록 하기 위해서 필요하다.
  • 인증에 필요한 것은 무엇이 있나?
    • 아이디, 이메일주소, 비밀번호 등
    • 이중에서 가장 중요한 것은? 비밀번호

간단하게 로그인 절차를 알아보자

  1. 유저 아이디와 비번 생성
  2. 유저 비번 암호화해서 DB에 저장
  3. 유저 로그인 -> 아이디와 비밀번호 입력
  4. 유저가 입력한 비밀번호 암호화 한후 암호화되서 DB에 저정된 유저 비밀번호와 비교.
  5. 일치하면 로그인 성공
  6. 로그인 성공하면 access token을 클라이언트에게 전송.
  7. 유저는 로그인 성공후 다음부터는 access token을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.

비밀번호는 어떻게 관리할까?

  • 법규상 강제하는 부분을 간단히 말해보자
    • 데이터베이스에 저장시 개인정보를 해싱하여 복원할 수 없도록 해야한다.
    • 통신시 개인정보를 주고받을때 SSL을 적용하여 암호화 (HTTPS)

암호화는 어떻게 할까? (단방향 해쉬란 뭐지?)

  • 유저의 비밀번호는 절대 비밀번호 그대로 DB에 저장하지 않는다.

    • DB가 해킹 당하면 비밀번호가 노출되고, 외부 해킹이 아니라 내부 개발자나 인력도 비밀번호를 볼수 있기때문에
  • 그러므로 유저의 비밀번호를 암호화해서 저장해서 DB가 해킹을 당해도 그대로 노출되지 않고 내부 인력도 비밀번호를 알 수 없다.

  • 본래 해쉬(hash)함수는 자료구조에서 빠른 자료의 검색, 데이터의 위변조 체크를 위해서 쓰이지만, 복원이 불가능한 단방향 해쉬함수는 암호학적 용도로 사용된다.

    • (MD5, SHA-1) - 보안취약 / SHA-256 등이 있다.
  • '1234'를 SHA-256으로 해싱하면 03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4 라는 값을 얻을 수 있다.

  • 결과만 보면 식별이 불가능하지만, 같은 알고리즘으로 '1234'를 다시 해싱하면 항상 같은 결과가 도출된다.

  • 이런 허점을 이용해서 가능한 경우의 수를 모두 해시값으로 만들어서 판매하는 서비스도 존재한다. (Rainbow Table)

  • 이런 Rainbow Table을 이용해서 해시값을 유추해주는 사이트도 존재한다.

  • 이같은 허점을 보호하고자 salting과 Key Stretching 이라는 아이디어가 생겨났다. 비밀번호와 임의로 생성한 문자열(Salt)를 합쳐서 해싱하여 이 해싱값을 저장하는 방법이다.

SALTING & KeyStretching?

  • 단순 해쉬값이 해킹에 쉽게 노출되므로 Salting이라는 아이디어가 생겨났다.
  • 입력한 비밀번호와 임의로 생성한 문자열(Salt)를 합쳐서 해싱해서 이 해시값을 저장하는 방법이다.
  • 물론 이때 비교를 위해 해시값과 소금값을 같이 저장해야한다.
  • 여기에 해커가 패스워드를 무작위 대입을 통해 해시값을 계산하는데 필요한 시간을 대폭 늘리기 위해서 Salting 및 해싱을 여러번 반복해서 원본 값을 유추하기 어렵게 만드는게 키 스트렛칭이다.

bcrypt

  • Salting & Key Stretching 대표적 라이브러리
  • bcrypt는 위에서 말한 개념들을 실제로 적용하기 편하게 해주는 대표적인 라이브러리이다.
  • 다양한 언어를 지원하고 사용이 간편해 쉽게 적용이 가능하다.
  • bcrypt 는 hash결과값에 소금값과 해시값 및 반복횟수를 같이 보관하기 때문에 비밀번호 해싱을 적용하는데 있어 DB설계를 복잡하게 할 필요가 없다.
  • bcrypt를 통해 해싱된 결과 값(Digest)의 구조는 아래와 같다.

인가(Authorization)는 무엇일까?

  • 사용자가 서버에 로그인 하면 해당 사용자가 맞는지 확인하는 과정이 바로 인가이다.
  • Http의 특징은?
    • request / response - 요청과 응답
    • stateless 성질 (저장하지 않는 성질)
  • 위의 특징때문에 서버는 사용자가 로그인 했을 경우, 로그인 했다는 것을 headers에 메타데이터를 보내서 확인한다.
  • 이 메타정보를 바로 JSON Web Token. 일명 JWT라고 한다.

JSON Web Token

  • 생성된 JWT의 예시
    • eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6Mn0.TqNLDeEa gjSeV6UozaejHx-xOWuzu_6XPHFRvW76Ong
      • eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 : 헤더(header)
      • eyJpZCI6Mn0 : 내용(payload)
      • TqNLDeEa gjSeV6UozaejHx-xOWuzu_6XPHFRvW76Ong : 서명(signature)

  • 위의 그림은 JWT의 구조이다.

  • 헤더에는 어떤 정보가 들어갈까?

    • 토큰의 타입해시알고리즘 정보가 들어간다.
    • 헤더의 내용은 BASE64방식으로 인코딩해서 JWT의 가장 첫 부분에 기록된다.
      - 예) {"alg": "HS256", "typ": "JWT"}

  • 다음으로 내용(payload) 은 무엇이 들어갈까?

  • 내용에는 exp와 같이 만료시간을 나타내는 공개 클레임클라이언트와 서버간 협의하에 사용하는 비공개 클레임. 이 두가지 요소를 조합하여 작성한 뒤, BASE64 인코딩하여 두번째 요소로 위치한다.

    • 예) {"user-id":1, "exp":1539517391}

  • 마지막은 서명(signature) 이다.
  • JWT가 원본 그대로라는 것은 확인할 때 사용하는 부분이다.
  • 서명은 BASE64URL 인코드된 headerpayload 그리고 JWT secret(별도 생성) 을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송한다. (복호화 가능)
  • 프론트엔드가 JWT를 백엔드 API 서버로 전송하면 서버에서는 전송받은 JWT의 서명부분을 복호화하여 서버에서 생성한 JWT가 맞는지 확인한다.
  • 계약서의 위변조를 막기위해서로 사인하는 것과 같다고 보면 된다.
  • 주의할 점은 header와 payload는 BASE64 인코딩한 것이므로(암호화가 아니다!) 누구나 원본을 볼 수 있으니 개인정보를 담아서는 안된다.

Authorization 절차

  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) 혹은 다른 에러 코드를 보낸다.

profile
이제 막 배우기 시작한 개발자입니다.

0개의 댓글