인증 & 인가

younghyun·2022년 2월 26일
0

암호화(Encryption) & 복호화(Decryption)

암호화

평문을 암호문으로 변환하는 과정
Ex) 평문("123456") → 암호화 → 암호문("aBD#fefa$fae!")

복호화

암호문을 평문으로 변환하는 과정
Ex) 암호문("aBD#fefa$fae!!") → 복호화→ 평문("123456")

암호화 종류

단방향 암호화

암호화 후 복호화 불가
Ex) 사용자 비밀번호 - 사용자가 입력한 비밀번호를 암호화 하여 DB에 저장이 될때, 모든 접근자(개발자포함)는 암호화 된 코드를 다시 평문으로 볼 수 없음. 또한, 해킹이 되어도 복호화가 매우 힘듦. (예외 - RainbowTable) 

양방향 암호화

암호화와 복호화 모두 가능
Ex) 사용자 주소, 이메일, 번호 또는 전자서명 같이 재사용성이 있는 정보는 암호화 복호화 모두 이루어져야함.

  • 대칭형(비밀키 암호) : 암호화 할때 사용한 key == 복호화 할때 사용하는 key 
    주로 데이터 통신 암호화에 많이 쓰임.

  • 비대칭형(공개키 암호) : 암호화 할때 사용한 key != 복호화 할때 사용하는 key
    주로 인증에 많이 쓰임.

암호 알고리즘

사용자가 정보를 입력하여 DB로 전달 되기 전에, 입력 값(평문)을 암호문으로 변경 해주는 알고리즘이 있음

알고리즘(단방향)

알고리즘은 다양함. 그 중 가장 많이 쓰이는 해시함수 알고리즘이 적용된 것만 서술.

  • 해시 함수
    임의의 길이의 데이터를 입력받아 일정한 길이의 비트열로 반환 시켜주는 함수로 입력값의 길이가 달라도 출력값은 언제나 고정된 길이로 반환되며 동일한 값이 입력되면 언제나 동일한 출력값을 보장하는 함수 의미함.

단방향 해시 함수 단점
1. 레인보우 테이블 공격
2. 무차별 대입 공격 ( 브루트 포스 )

단방향 해시 함수 보완
1. Key Stretching : 단방향 해쉬값을 계산 한 후 그 해쉬값을 또 해쉬 하고, 또 이를 반복하는 것
2. Salting : 실제 비밀번호 이외에 추가적으로 랜덤 데이터를 더해서 해시값을 계산하는 방법.

  • SHA(대표적인 해시함수의 시초 since 1993)

  • MD5

  • PBKDF2
    해시 함수의 컨테이너인 PBKDF2는 솔트를 적용한 후 해시 함수의 반복 횟수를 임의로 선택할 수 있음. PBKDF2는 아주 가볍고 구현하기 쉬우며, SHA와 같이 검증된 해시 함수만을 사용함.(Django 에서 사용) 

  • bcrypt
    Salting과 Key Stretching을 구현한 해쉬 함수중 가장 널리 사용되는 것. bcrypt는 처음부터 비밀번호를 단방향 암호화 하기 위해 만들이전 해쉬함수. bcrypt는 보안에 집착하기로 유명한 OpenBSD에서 기본 암호 인증 메커니즘으로 사용되고 있고 미래에 PBKDF2보다 더 경쟁력이 있다고 여겨짐. 입력값을 72 byte로 해야 해서 조금 귀찮음. 하지만 가장 많이 쓰임.

  • scrypt
    scrypt는 상대적으로 최신 알고리즘이며 나머지 둘보다 더 경쟁력 있는 것으로 평가되나, 아직 덜 확산되어 있음. scrypt는 다이제스트(해시 함수라는 수학적인 연산을 통해 생성된 암호화된 메세지)를 생성할 때 메모리 오버헤드를 갖도록 설계되어, 억지 기법 공격(brute-force attack)을 시도할 때 병렬화 처리가 매우 어려움. 따라서 PBKDF2보다 안전하다고 평가되며 미래에 bcrypt에 비해 더 경쟁력이 있다고 여겨짐.

알고리즘(양방향)

  • 대칭형(비밀키 암호) 알고리즘

    암호화, 복호화에 서로 동일한 키가 사용되는 암호화 방식으로 키를 비공개하는 것이 특징.
    속도가 빠르다는 장점이 존재하지만 키 배송 위험성이 존재하여 송신측에서 수신측에 암호키를 전달하는 과정에서 키가 노출될 우려가 있다는 단점이 존재.
    송신 측은 수신 측에 암호키를 전달해야만 하고, 이 키가 배송과정에서 털리게 되면 아무리 뛰어난 암호화 알고리즘을 사용했더라도 속절없이 평문이 드러나게 됨.
    안전하게 평문을 전달하기 위해 만든 것이 암호문인데, 정작 키는 안전하게 전달할 방법이 없다는 것이 가장 큰 단점.
    키 배송에 대한 방법이 여러가지 연구되었지만 결국 발상의 전환으로 키 배송 문제를 해결하기 위해 나타난 방식이 바로 비대칭형 암호.

a. AES
현재 가장 보편적으로 쓰이는 암호화 방식은 현 미국 표준 방식. 128~256비트 키를 적용할수 있어 보안성이 뛰어나며 공개된 알고리즘이라 누구나 사용할 수 있음.

  • 비대칭형(공개키 암호)알고리즘

    암호화, 복호화에 서로 다른 키가 사용되는 방식으로 하나의 키는 공개키로 사용하는 것이 특징. 키 배송의 문제를 근본적으로 차단하여 안정성이 높지만 대칭키 방식에 비해 속도가 느리다는 단점이 존재.
    현실적으로는 비대칭형 암호를 이용해 대칭형 암호의 키를 배송하고 실제 암호문은 대칭형 암호를 사용하는 식으로 상호 보완적으로 이용하는 것이 일반적.
    비대칭형 암호도 약점은 중간자 공격 (해커가 중간에서 통신을 가로채어 수신자에게는 송신자인 척하고 송신자에게는 수신자인 척 해서 양쪽의 공개키와 실제 암호화에 사용되는 대칭키를 모두 얻어내는 기법)

a. RSA
공개키 암호시스템의 하나로 암호화뿐만 아니라 전자서명이 가능한 최초의 알고리즘.
주로 적은양의 데이터나 전자서명에 사용. 대칭키인 DES, AES보다 속도가 느리기 때문에 메시지 암호화에는 쓰이지 않고 주로 키를 암호화하는데에 사용

인증(Authentication)

유저의 identification(아이디, 비번) 확인하는 절차
서비스를 누가쓰며, 추적이 가능하도록 하기 위해 필요

1 - 1 로그인 절차

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

1 - 2 유저 비밀번호 암호화

  • 유저의 비밀번호는 절대 비밀번호 그대로 DB에 저장 하지 않는다.
    • DB가 해킹을 당하면 유저의 비밀번호도 그대로 노출 된다.
    • 외부 해킹이 아니더라도 내부 개발자나 인력이 유저들의 비밀번호를 볼 수 있다.
  • 유저의 비밀번호는 꼭 암호화 해서 저장 해야 한다.
    • 그럼으로 DB가 해킹을 당해도 비밀번호가 그대로 노출되지 않으며
    • 내부 인력도 비밀번호를 알 수가 없음.
  • 비밀번호 암호에는 단방향 해쉬 함수(one-way hash function)가 일반적으로 쓰인다.
    • 단방향 해시 함수는 원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest)를 생성한다. 원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 암호화된 메시지로는 원본 메시지를 구할 수 없어서 단방향성(one-way) 이라고 한다.
    • 예를 들어, "test password"를 hash256이라는 해쉬 함수를 사용하면 0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e 값이 나온다.
    • 만일 "test password2"를 hash256 해쉬 함수를 사용하면 d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb 값이 나온다. 실제 비밀번호는 비슷하지만 해쉬 함수 값은 완전히 틀린것을 볼 수 있다. 이러한 효과를 avalance라고 하는데 비밀번호 해쉬 값을 해킹을 어렵게 만드는 하나의 요소이다.

JWT(JSON Web Tokens)

앞서 언급했듯이 유저가 로그인에 성공한 후에는 access token이라고 하는 암호화된 유저 정보를 첨부해서 request를 보내게 된다.

유저 로그인

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"
}

그러면 서버에서는 access token을 복호화 해서 해당 유저 정보를 얻게 된다.

예를 들어 access token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E 를 복호화 하면 다음과 같은 정보를 얻는다:

{
    user_id = 1 
}

복호화해서 얻은 유저 아이디를 통해 해당 유저가 누군지 알 수 있다.
이런 절차의 목적은 해당 유저가 매번 로그인 하지 않도록 하는 것이다.

access token을 생성하는 방법은 여러가지가 있는데, 그 중 가장 널리 사용되는 기술중 하나가 바로 JWT(JSON Web Tokens)이다.

JWT는 말 그대로 유저 정보를 담음 JSON 데이터를 암호화 해서 클라이언트와 서버간에 주고 받는 것이다.

인가(Authorization)

해당 유저가 request에 권한이 있는지 확인하는 절차
Token을 활용해 인가하여 http 특징 중 요청과 응답, stateless 문제를 해결함.
access token을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)도 확인 할 수 있다

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

참고
https://sieunlim.tistory.com/16
https://www.zehye.kr/etc/2021/09/15/etc_encryt/
https://st-lab.tistory.com/100

profile
선명한 기억보다 흐릿한 메모

0개의 댓글