질문! '인증'이란 무엇인가요? '인가'는 무엇이죠?'
제가 이 질문을 처음 들었을때는 무언가 다르다는건 느낌상 알겠는데, 질문을 듣고 정확하게 바로 뭐다!
라고 말하기엔 곤란했던 질문이였습니다.
그래서 인스타그램의 예를 들어서 인증(Authentication)과 인가(Authorization)의 차이점에 대해서 정리했습니다.
인스타그램에서 회원가입을 하고 로그인을 한다음 사진 하나를 업로드 한다고 가정해 봅시다.
여기서 인증(Authentication)은 사용자가 로그인을 시도했을 경우, 인스타그램에 가입(등록)한 사용자인지 확인하는것이 인증입니다.
인가(Authorization)는 로그인을 하고 나서, 사진을 업로드 하는것 입니다.
즉, 로그인한 회원(인증된 사용자)에게 부여된 권한에 따라서 사진을 업로드 한것이죠
인증은 유저의 identification을 확인하는 절차인데, 간단하게 로그인을 생각하면 된다고 했습니다. 그러면 유저가 로그인을 시도하면 무슨 일이 일어 날까요?
유저가 로그인을 시도하려면 우선 회원가입이 선행되어야 합니다.
회원가입을 하게되면 유저의 비밀번호는 암호화 되어 데이터베이스(DB)에 저장됩니다.
1) 유저가 아이디와 비밀번호를 입력하여 로그인을 시도
2) 유저가 입력한 비밀번호는 암호화 되어서 DB에 암호화 되어 저장된 비밀번호와 같은지 비교합니다.
3) 유저가 입력한 비밀번호와 DB에 저장된 비밀번호가 같으면 access token
을 클라이언트에게 전송합니다.
4) 유저는 로그인에 성공한 후, 다음 요청(request)부터는 access token
을 request에 첨부해서 서버에 전송함으로 매번 번거롭게 로그인 할 필요가 없습니다.
access token
을 생성하는 방법에는 여러 방법이 있는데, 그중 가장 널리 사용되는 기술 중 하나가 JWT(JSON Web Tokens)
입니다.
JWT는 클라이언트와 서버간에 유저 정보를 담은 JSON 데이터를 암호화 해서 주고 받는것 입니다.
1) 유저의 비밀번호는 암호화하여 DB에 저장합니다.
2) 비밀번호 암호에는 일반적으로 단방향 해시 함수(one-way hash function)가 쓰입니다.
단방향 해시 함수는 원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest)를 생성 합니다. 원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 암호화된 메시지로는 원본 메시지를 구할 수 없어서 단방향성(one-way) 이라고 합니다.
"test password"를 hash256이라는 해시 함수를 사용하면 0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e
값이 나옵니다.
"test password2"를 hash256 해쉬 함수를 사용하면 d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb
값이 나옵니다.
실제 비밀번호는 비슷하지만 해시 함수 값은 완전히 다른것을 볼 수 있는데, 이러한 효과를 avalance
라고 하며, 암호화된 비밀번호의 해시 값이 노출되더라도 해킹하기 어렵게 만드는 하나의 요소입니다.
Rainbow table attack
미리 해쉬값들을 계산해 놓은 테이블을 Rainbow table이라고 합니다.
Rainbow table에서 암호된 비밀번호의 해시값을 확인해서 복호화가 가능합니다.
해시 함수는 원래 비밀번호를 저장하기 위해서 설계된 것이 아니라 짧은 시간에 데이터를 검색하기 위해 설계된 것이기 때문에 해시 함수는 처리 속도가 빠릅니다. 그리고 이러한 속성 때문에 해커는 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교할 수 있습니다.(MD5를 사용한 경우 일반적인 장비를 이용하여 1초당 56억 개의 다이제스트를 대입할 수 있다)
만약 이런 방식으로 패스워드를 추측한다면 패스워드가 충분히 길거나 복잡하지 않은 경우, 해킹하는데 그리 긴 시간이 걸리지 않게 됩니다. 심지어 대부분 사용자는 사용하는 비밀번호가 길거나 복잡하지 않을 뿐 아니라, 동일한 패스워드를 사용하는 경우도 많기에 보안에 취약합니다.
단방향 해쉬 함수의 취약점들을 보완하기 위해 일반적으로 Salting
과Key Stretching
이 동시에 사용 됩니다.
Salting
실제 비밀번호에 추가적인 랜덤 데이터를 더해서 해시값을 계산하는 방법으로 실제 유저 비밀번호가 무엇인지 찾기 어렵게 만드는 방법입니다.
Key Stretching
단방향 해시값을 계산 한 후, 그 해시값을 수 차례 해싱하여 처음의 해시값을 알기 어렵게 하는 방법입니다.
Salting
과 Key Stretching
을 구현한 해시 함수중 가장 널리 사용되는 것이 bcrypt
이며,
bcrypt
는 비밀번호를 단방향 암호화 하기 위해 만든 해시함수 입니다.
인가는 유저가 요청한 request를 실행할 수 있는 권한을 가진 유저인지 확인하는 절차입니다.
인가도 JWT를 통해서 구현 될 수 있습니다.
access token
을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)
도 확인 할 수 있습니다.
1) 인증 절차를 통해 access token
을 생성합니다. access token
에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 합니다 (예를 들어 user id).
2) 유저가 request를 보낼때 access token을 첨부
해서 보낸다.
3) 서버에서는 유저가 보낸 access token을 복호화
하고, 복호화된 데이터를 통해 user id를 얻습니다.
4) user id를 사용해서 데이터베이스에 해당 유저의 권한(permission)을 확인
합니다.
5-1) 유저가 보낸 요청에 대해서 권한을 가지고 있으면 해당 요청을 처리
합니다.
5-2) 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드
를 보냅니다.