-
패스워드 암호화(해시, 솔트, 키스트레칭)ETC 2022. 6. 28. 03:01
파이널 프로젝트 진행 중,
회원의 패스워드는 절대로 원본 자체를 DB에 저장하면 안된다는 강사님의 말씀을 듣고
암호화에 대해 공부해봤다.
일반적으로 패스워드 암호화는 해시함수를 통해 구현한다.
여기서 해싱이란?
이렇게 원본 텍스트를 알아볼 수 없는 문자열로 변환하는 작업을 의미한다.
엄밀히 말하면, 해싱과 암호화는 다르다.
암호화는 이 과정에서 복호화(encryption, decryption)을 거친다.
일반적으로 많이 사용되는 단방향 해시함수와 암호화의 가장 큰 차이점은,
단방향 해시함수는 원본 문자열의 복원이 불가하지만, 암호화는 복호화키를 사용해 평문으로 복원이 가능하다는 점이다.
예를들어, 1234라는 암호를 xzetjiosz#$7895dsfkjl; 라는 문자열로 변환했다면,
단방향 해시함수는 이 문자열로 1234를 얻어내는 것이 불가능하지만, 암호화는 가능하다.
두 가지의 특징을 생각해보면, 회원의 패스워드는 어떠한 경우에서든 다른 사람이 평문으로 복원하면 안되기 때문에 단방향 해시함수를 많이 이용하는 것 같다.
해싱 알고리즘 또한 굉장히 여러종류가 있는데, 그 중 많이 사용되는 알고리즘으로 SHA-256 방식이 있다.
단방향 해시함수의 취약점?
단방향 해시함수는 한가지 취약점이 있는데, 동일한 패스워드에 대해 동일한 해싱값을 반환한다는 점이다.
만약 user1이 비밀번호 1234로 회원가입을 하고, user2가 우연히 동일한 패스워드인 1234로 가입을 했을 때,
두 사람의 해싱값은 동일하다.
이는 이미 수많은 해커들의 해킹시도로 데이터가 누적되었고, 레인보우 테이블(Rainbow Table)이라는 이름으로 공유되고 있다. sha-256 rainbow table을 검색하면 나오는 사이트에서, 해싱값을 넣으면 자동으로 평문으로 복원해주는 사이트까지 있다.
이렇게 되면 평문을 얻어낼 수 없다라는 단방향 해시함수의 특징 자체가 무력화 된다. 만약 SHA-256 함수를 사용한 어떤 사이트의 DB가 유출되어, 회원들의 패스워드를 레인보우 테이블에서 찾으면 해당 사이트의 모든 회원의 패스워드를 알아낼 수 있다. 실제로 일어난다면... 보안 이슈로 뉴스에 나올만한 문제다.
단방향 해시함수의 보완 : 1. 키 스트레칭(Key Stretching)
이를 보완하는 방법 첫번째로 키 스트레칭 기법이 있다.
정말 단순하게, 해싱된 값을 다시 해시함수에 돌리는 것을 n번 반복하는 기법이다.
단순히 한번만 수행하는 것에 비해 반복횟수를 알아내야한다는 제약조건이 추가되고,
만약 알아냈더라도 평문으로 변환하는 과정이 오래걸려 더 안전하다.
그러나 같은 암호에 대해 같은 해시값을 반환한다는 근본적인 문제는 해결할 수 없다.
단방향 해시함수의 보완 : 2. 솔트(Salt)
이 문제를 해결하기 위해 솔트기법이 생겨났다.
솔트(salt)는 소금, 단어 그대로 양념친다는 의미다.
무작위 16진수를 생성해서 입력받은 패스워드 뒤에 붙이고, 결합된 문자열을 가지고 해싱하는 기법이다.
이렇게하면 동일한 패스워드인 1234로 회원가입을 해도, 저장되는 패스워드는 모두 다르다. 규칙성이 없기 때문에 레인보우 테이블 자체를 만들 수 없다.
이 방법을 처음 보고 '되게 좋은 방법이다! 근데 무작위로 솔트값이 생성되는데 그럼 로그인할 땐 어떻게 일치여부를 확인할까?'라는 생각이 들었다.
원리는 간단했다.
회원가입 시에 생성된 솔트값을 DB에 함께 저장하면 된다.
회원ID, 회원PW, 회원SALT 이렇게 3가지를 저장하게 되는 것!
로그인시에는 ID에 해당하는 SALT를 얻어와서, 그 솔트값을 패스워드에 붙여 해싱한 결과와 DB의 패스워드를 대조하게 된다.
어처피 DB에 저장되는 패스워드는 (패스워드+솔트)를 해싱한 값이기 때문에, 이렇게하면 DB가 유출되어도 평문을 알아낼 방법이 없다.
결론 : 단방향 해시함수 + 솔트 + 키 스트레칭을 사용해보자
(패스워드 + 솔트)를 단방향 해시함수에 넣고, 이 과정을 n번 반복하면 위의 모든 방법을 합친 기법이 된다.
물론 이 방법도 취약점이 존재할거 같긴 하지만 웬만해선 쉽게 정보를 얻어내진 못할 것이다.
자바에서는 SHA-256 해싱 알고리즘을 라이브러리로 제공하고 있기 때문에, 프로젝트에서 암호화할 때 이 기법을 사용해보려고 한다. 이 외에도 bcrypt라는 암호화 방법에 대해 찾아봤는데(이것도 spring에서 제공한다.) 솔트를 붙여 암호화한다는 프로세스는 비슷한 것 같다. crypt라는 이름에서 알 수 있듯 해싱이 아닌 암호화의 일종이다. SHA-256보다 더 좋다는 의견도 있지만 국내 암호화 표준이 아니라는 얘기도 있어서.. 지금으로서는 뭐가 정확한 정보인지 판별할 수 있는 능력이 없기 때문에 가장 보편적인 이 방법을 택했다.
마지막으로 공부한 내용을 토대로 프로젝트의 회원가입/로그인 프로세스를 정리해봤다.
+) 여담
더보기보안에 대해 깊게 생각해본 적이 없었는데, 이번 기회에 이것저것 알아보는 과정이 꽤 흥미로웠다.
그래서 해시 알고리즘이 대체 뭐고 어떤 원리에 의해 구현이 되는가가 좀 궁금해서 잠깐 알아봤다가
그만 알아봐도 될거 같아서 멈췄다. 멈춰!!!!!
내부 알고리즘이 어떻게 작동하는가는 몰라도, 그 알고리즘을 선택해서 어떻게 보안을 강화하고, 또 데이터를 어떻게 저장해서 대조할 것인지를 알아보는 과정은 매우 재밌었고, 의미있는 시간이었다.
'ETC' 카테고리의 다른 글
[nGrinder] 서버 성능을 테스트하는 방법 (0) 2022.12.20 java.lang.NoClassDefFoundError 원인 및 해결방법 (0) 2022.12.19 Callback 함수란 무엇인가? 재귀함수와의 차이는? (0) 2022.10.03 [HTML/CSS] 입력폼 유효성 검사에 필요한 input태그 pattern 속성 (0) 2022.07.07