[TIL]인증&인가(Authentication & Authorization)

여주링·2020년 12월 10일
2

WECODE

목록 보기
9/10
post-custom-banner

로그인 절차

  1. 유저 아이디와 비번 생성.
  2. 유저 비번 암호화해서 DB에 저장.
  3. 유저 로그인(아이디와 비밀번호 입력)
  4. 유저가 입력한 비밀번호를 암호화하여 DB에 저장된 유저 비밀번호와 비교.
  5. 일치하면 로그인 성공
  6. 로그인 성공시, access token을 클라이언트에게 전송. (이게 끝나면 access token을 첨부해서 request를 서버에 전송함으로 매번 로그인하지 안해도 된다)

    이번 세션에서 배운건 굵게처리된 4,5,6번에 관련 된 내용이다!

<인증(Authentication)>

인증은 회원가입과 로그인을 말한다. 왜 필요할까? 우리 서비스의 이용여부와, 사용패턴 분석등을 확인가능하게 하며, 나아가 장기적인 목표를 세우는데 도움이 될 수 있다.

  • 인증에 필요한 것 : 아이디, 이메일주소, 비밀번호 등이 있다
    이중 가장 중요한 건 비밀번호!!

1. 비밀번호

비밀번호는 개발자가 깊이 관리를 하는 분야이다 왜일까?
-> 개인정보를 보호해야하며 해킹의 위협으로부터 안전해야 하기 때문!!

비밀번호의 저장방법

  • Database에 저장시 개인정보를 해싱하여 애초에 복원할 수 없도록 함. 이방법의 경우 백엔드개발자도 실제 비밀번호를 모르는거..ㅎ
    저 비밀번호를 진짜 치는 사람이 있을리가
  • 통신시 개인정보를 주고받을때 SSL을 적용하여 암호화(HTTPS)

2. 암호화의 방법

사용자가 입력한 그대로 패스워드를 저장한다고 생각해보자. 단언컨데 털리는 사이트 1순위일듯..

단방향 해시(hash)란?

암호화를 할때 해시를 이용한다. 해시란,컴퓨터 공학의 데이터 구조에 있는 자료형 중의 하나로 자료의 검색, 데이터의 위변조 체크를 위해 쓰이지만 암호학적 용도로도 사용된다.
단방향 해시 함수는 수학적인 연산을 통해 원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest)를 생성한다. 원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 암호화된 메시지로는 원본 메시지를 구할 수 없어야 하며 이를 단방향성이라고 한다.

예를 들어 사용자의 패스워드가 hunter2라면 이 문자열을 흔히 사용하는 해시 알고리즘인 SHA-256으로 인코딩하여 아래와 같은 값을 얻을 수 있다.

f52fbd32b2b3b86ff88ef6c490628285f482af15ddcb29541f94bcf526a3f6c7 

위의 값을 저장하면 사용자의 패스워드를 직접 저장하는 위험을 피할 수 있다. 그리고 사용자가 로그인할 때 패스워드를 입력하면, 이를 해시한 값을 저장된 값과 비교하여 일치 여부를 확인할 수 있다.

단방향 해시 함수의 문제점

대부분의 웹 사이트에서는 SHA-256과 같은 해시 함수를 사용해 패스워드를 암호화해 저장하고 값을 비교하는 것만으로 충분한 암호화 메커니즘을 적용했다고 생각하지만, 실제로는 다음과 같은 두 가지 문제점이 있다.

첫번째. 인식 가능성(recognizability)
동일한 메시지가 언제나 동일한 다이제스트를 갖는다면, 공격자가 다이제스트를 가능한 한 많이 확보한 다음 다이제스트와 비교해 원본 메시지를 찾아내거나 동일한 효과의 메시지를 찾을 수 있다. 이와 같은 다이제스트 목록을 레인보우 테이블(rainbow table)이라 하고, 이와 같은 공격 방식을 레인보우 공격(rainbow attack)이라 한다. 게다가 다른 사용자의 패스워드가 같으면 다이제스트도 같으므로 한꺼번에 모두 정보가 탈취될 수 있다.

내가 설정한 '1234', 다른 사람이 설정한 '1234'의 다이제스트는 동일 -> 그냥 하나하나 입력하면서 해킹해도 되는것..;

두번째. 속도(speed)
해시 함수는 암호학에서 널리 사용되지만 원래 패스워드를 저장하기 위해서 설계된 것이 아닌 짧은 시간에 데이터를 검색하기 위해 설계되었다고 한다. 해시 함수의 빠른 처리 속도로 인해 공격자는 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교할 수 있다(MD5를 사용한 경우 일반적인 장비를 이용하여 1초당 56억 개의 다이제스트를 대입할 수 있다고...;;) 즉 복잡하지 않은 단순한 패스워드 혹은 짧은 패스워드는 그냥 몇분 만에 털릴 수 있는거다..ㅠㅠ
해시 함수의 빠른 처리 속도는 사용자에게는 별 상관이 없지만(0.1초,1초의 차이.. 잘 모르지 않을까..)공격자들에게는 해시 함수의 속도가 엄청난 편의성이 생기게 되고 여기서 위와같은 문제점들이 발생하게 되었다

3. SALTING & KeyStretching

해시 함수의 허점을 보완하고자 salting과 key stretching이라는 아이디어가 생겨났다.

솔팅(salting)

갑분소금..?(우리가 생각하는 그 소금맞아요~)

솔트(salt)는 단방향 해시 함수에서 다이제스트를 생성할 때 추가되는 바이트 단위의 임의의 문자열이다. 그리고 이 원본 메시지에 문자열을 추가하여 다이제스트를 생성하는 것을 솔팅(salting)이라 한다.(백엔드 개발자도 뭐가 어떻게 나올지 모르고, 본인이 정할 수 없음)
위의 예시와 같이 "redfl0wer"에 솔트인 "8zff4fgflgfd93fgdl4fgdgf4mlf45p1"를 추가해 다이제스트를 생성할 수 있다.
이 방법을 사용하면, 공격자가 "redfl0wer"의 다이제스트를 알아내더라도 솔팅된 다이제스트를 대상으로 패스워드 일치 여부를 확인하기 어렵다. 또한 사용자별로 다른 솔트를 사용한다면 동일한 패스워드를 사용하는 사용자의 다이제스트가 다르게 생성되어 인식 가능성 문제가 크게 개선된다. (사용할 때에는 모든 패스워드가 고유의 솔트를 갖고 솔트의 길이는 32바이트 이상이어야 솔트와 다이제스트를 추측하기 어렵다고 한다)

키 스트레칭(key stretching)

입력한 패스워드의 다이제스트를 생성하고, 생성된 다이제스트를 입력 값으로 하여 또 반복하는 방법으로 다이제스트를 생성할 수도 있다. 2중으로 다이제스트를 하는것!! 이렇게 하면 입력한 패스워드를 동일한 횟수만큼 해시해야만 입력한 패스워드의 일치 여부를 확인할 수 있다. 이것이 기본적인 키 스트레칭 과정이다.

왜?
이는 억지 기법 공격(brute-force attack)으로 패스워드를 추측하는 데 많은 시간이 소요되도록 하기 위한 것
하나로 꼬는것보다 두세번꼬는게 더 풀기 힘드니까~

<추가내용>
최근에는 일반적인 장비로 1초에 50억 개 이상의 다이제스트를 비교할 수 있지만, 키 스트레칭을 적용하여 동일한 장비에서 1초에 5번 정도만 비교할 수 있게 한다. GPU(Graphics Processing Unit)를 사용하더라도 수백에서 수천 번 정도만 비교할 수 있다. 50억 번과는 비교할 수도 없을 정도로 적은 횟수다. 앞으로 컴퓨터 성능이 더 향상되면 몇 번의 반복을 추가하여 보완할 수 있다.
출처, 네이버

솔트를 추가한 패스워드에 여러 단계의 해시 함수를 적용하여 다이제스트를 생성하는 과정은 아래의 그림과 같다

4. 암호화 시스템

최근 웹사이트들은 자신만의 암호화 시스템을 구현을 하는것보다 널리 알려진 검증된 시스템을 사용하고 있다. 왜냐, 독자적으로 암호화 시스템을 잘못 구현해서 발생하는 위험을 피할 수 있기 때문이다.

bcrypt

Salting & Key Stretching의 대표적 라이브러리

bcrypt는 애초부터 패스워드 저장을 목적으로 설계된 라이브러리이다. 1999년 발표되었고 오늘날 많이 사용되는 가장 강력한 해시 메커니즘 중 하나이다. bcrypt는 다이제스트에 솔트값+해시값+반복변수 다같이 보관해주기 때문에 DB설계를 복잡하게 할 필요가 없다!

<인가(Authorization)>

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

왜 필요할까? Http의 특성때문인데, 1)요청&응답 2)stateless한 성질 때문이다.

ex)넷플릭스의 경우. 유저(가입,결제했어~)->넷플릭스에서 콘텐츠를 볼수있게 해주는거!
ex)1. 유저로그인->서버에서 확인후 200 OK와 Token을 발행해준다
2. 로그인한유저가 뭔가를 시도했다(줌에 들어간다던지 콘텐츠를 열어본다던지)->우리서버는 1번에서한걸 싹다 까먹은 상태이므로 1번에서 발급받은 Token을 같이 주며 요청을 해서 '아 유저였지~'라고 기억할수 있게 해준다

위 예시의 Token은 headers의 메타데이터로 포함된다. 또한 메타정보(예시의 Token)를 바로 JSON Web Token,JWT라고 한다(JMT,존맛탱아님)

(백엔드의 입장에서 보면 서버가 로그인의 결과로 프론트개발자에게 JWT을 리턴해준다고 이해하면 될듯. 그리고 이 토큰을 프론트앤드개발자들은 브라우저 저장소에 저장을 하고 다음 요청을 보낼때마다 그 저장소에 있는걸 친절하게 꺼내주는것~)

1. 인가 과정

위의 ex)를 세세하게 풀어본것
1.Authentication 절차를 통해 access token을 생성(access token에 :유저 정보를 확인할 수 있는 정보가 들어있어야 한다(ex.user id)) -> 이게 있어서 인가가 수월해짐(정보가 없는데 인가를 어떻게 합니까..)
2.유저가 request를 보낼시 access token을 첨부해서 보낸다.
3.서버에서는 유저가 보낸 access token을 복호화 한다.
4.복호화된 데이터를 통해 user id를 얻는다.
5.user id를 사용해서 database에서 해당 유저의 권한(permission)을 확인하다.
6.유저가 충분한 권한을 가지고 있으면 해당 요청을 처리 하고 권한을 가지고 있지 않으면 에러 코드를 보낸다(401같은 에러코드)

2. JSON Web Token(JWT)

  • Header : 토큰의 타입과 해시알고리즘 정보가 들어간다
  • Payload(내용) : 클라이언트와 서버간 합의하에 들어가는 비공개 클레임(정보)가 들어있다. 또한 익명성을 위해 적절히 정보를 조절해 송신한다. 토큰의 유효기간도 같이 들어간다 (카카오뱅크 15분이면 로그인 종료되게 해놓은것)
  • Signature(서명) : JWT가 원본 그대로라는걸 확인할 때 사용하는 사용. 인코딩(문자의 타입만 바꿔준)된 header과 payload인데, 원본이라는걸 지키기 위해 서명부분이 암호화를 한 채로 전송된다(이부분은 만든 회사에서만 열수있게 되어있음)

<결론>

  • 인증이란?
    유저가 누구인지 확인하는 절차, 회원가입하고 로그인 하는 것.

  • 인가란?
    유저에 대한 권한을 허락하는 것.

인증,인가의 절차를 요약해보면
클라이언트 요청 - 인증 - 비밀번호 암호화(bcrypt) - JSON 데이터(access token 전달) - 비밀번호 복호화 - 인가 - 요청 응답

(추가)
토큰은 인증인가의 수단일뿐! 인증도, 인가도 절차적용어라 헷갈리지말자!!

profile
🌱Backend Developer👩‍💻
post-custom-banner

0개의 댓글