탕구리's 블로그

Node.js Crypto 모듈 본문

javascript/Node.js

Node.js Crypto 모듈

탕구리당 2017. 12. 25. 17:24
반응형

시작하기 전에


해당 블로그에 작성되는 글은 주인장의 지극히 주관적인 생각이 다수이며, 대부분의 지식은 구글링을 통해 얻고 있기 때문에 옳지않은 정보가 있습니다. 

잘못된 부분이나 수정해야 하는 부분이 있다면 과감히 덧글을 남겨주세요! 모르는게 많은 새싹입니다



Crypto 모듈을 이용한 기초적인 단방향 암호화 


안녕하세요. 오랜만에(?) 거의 처음으로 Node.js 관련 포스팅을 해보네요!
업무를 진행하며(그래봤자 신입입니다)  Session 관련 업무를 맡게되어 보안적인 측면에도 신경을 쓰기위해(!)
공부하던 도중 Crypto 모듈에 관한 다양한 자료들을 읽던 도중 정리해두면 편리할 꺼 같아 포스팅을 하게 되었습니다.


암호화란?

간단하게 생각하면 내가 가진 정보를 다른사람이 알아보지 못하게 "난독화" 혹은 "나만의 비밀번호를 설정" 하는 과정이라고 생각하시면 편할것 같아요.


위키백과를 들여다 보면 아래와 같은 설명이 있습니다.


암호화(暗號化) 또는 엔크립션은 특별한 지식을 소유한 사람들을 제외하고는 누구든지 읽어볼 수 없도록 알고리즘을 이용하여 정보(평문을 가리킴)를 전달하는 과정이다. 이러한 과정을 통해 암호화된 정보(암호문)를 낳는다. 이에 역행하는 과정을 해독 또는 디크립션이라고 하며 이로써 암호화된 정보를 다시 읽을 수 있다. 



암호화 방식


암호화 방식은 크게 세가지로 분류할 수 있다는 글을 보았습니다. 단방향 암호화양방향 암호화 이며, 양방향 암호화대칭형 암호화비대칭형 암호화가 존재합니다. 대칭형 암호화와 비대칭형 암호화는 암호화할 때 사용하는 키와 복호화할 때 사용하는 키의 동일성(?)에 대한 기준으로 구분하게 됩니다.


그러면 단방향 암호화는 무엇일까? 단방향 암호화는 말 그대로 암호화만 가능하고 복호화(암호화한 내용을 다시 되돌리는것)가 불가능하게 함을 목표로 합니다.

단방향 암호화는 복호화가 불가능하기 때문에 복호화할 필요가 없는 정보를 암호화 하는데 사용합니다. 일반적으로 저희가 이용하는 웹 사이트에서 비밀번호는 한번 암호화 하면 복호화 할 필요가 없기 때문에 단방향 암호화를 이용하여 비밀번호를 암호화 시키고 사용자가 로그인을 할때는 입력받은 비밀번호를 다시 암호화하여 기존에 암호화 되었던 값과 비교를 통해 로그인 처리를 하게 됩니다.


저희는 오늘 단방향 암호화에 대한 실습을 할 예정입니다.(단방향 밖에 안해봤기 때문에)


단방향 암호화 해보기


우선, Node.js를 이용해 단방향 암호화를 하는 방법은 아.주. 무.지. 간.단. 합니다.

      const string = 'this is my password'
      //1. 단순 해싱으로 비밀번호 해싱
      let hashAlgorithm = crypto.createHash('sha512');
      //선택된 알고리즘으로 해싱
      let hashing = hashAlgorithm.update(string);
      //표시할 인코딩 설정. 
      let hashedString = hashing.digest('base64');


자! 이게 끝입니다


이제 실행되는 순서를 살펴 봅시다.


첫번째,  string 변수 안에 사용할 비밀번호를 입력 받습니다.

두번째, 사용할 해시함수를 선택합니다 위의 코드에서는 "sha512" 방식을 선택 하였습니다.

세번째, 선택한 해시함수와 나의 비밀번호를 해싱하는 과정을 실행합니다.

마지막으로 "base64"로의 인코딩 된 digest 코드를 만들어 냅니다. 

하지만 이러한 단순방식은 같은 알고리즘과 같은 인코딩 방식을 선택하여 암호화하면 같은 결과을 뱉어냅니다.

"레인보우 테이블"을 통해 해커는 암호화된 결과를 보고 원래의 비밀번호를 도출할 수 있습니다.



소금을 뿌려 해커를 방해하자.

이러한 단순 방식의 암호화는 해커에게 노출될 수 있습니다. 실제로 MD5, SHA-1 방식의 암호화는 이미 뚫려버린 사례가 있죠
그래서 우리는 복호화를 방해하기 위해 단방향 암호화시 소금(Salt)를 뿌려 해커가 복호화 하는 것을 방해합니다.
(저희는 복호화할 일이 없기 때문에 소금을 마구 뿌려 줍니다.)



이렇게 소금(salt)와 password를 섞어 해시함수에 넣어주면 기똥찬 digest가 나오게 됩니다.

모든 패스워드에 같은 소금정보를 사용하게 되면 해커가 한번 소금정보를 알아 냈을때 다른 비밀번호도 쉽게 뚫리겠죠?


이 문제를 해결하기 위해서 랜덤바이트를 생성하여 임의 소금정보를 생성하여 줍니다.

      crypto.randomBytes(32, function(err, buffer){
        //32bit 길이의 random byte 생성
        if(err){
          console.log(err);
        } else{ }})


이렇게 cryto모듈의 랜덤바이트 함수를 이용하면 32비트의 기똥찬 소금을 만들어 낼 수 있습니다.

랜덤바이트 함수의 콜백으로 err, buffer(이것을 나중에 base64로 인코딩할 겁니다!) 정보를 받게 됩니다.

그럼 이렇게 저희는 문자열과 솔트를 얻게 되었습니다.


해커를 좀 더 괴롭히는 키 스트레칭(Key Stretching)


우선 키 스트레칭이 뭔지 그림을 통해 알아봅시다.



대~~~충 그림만 봐도 느낌이 오죠? 키 스트레칭은 솔트와 패스워드를 해시함수에 넣는 과정을 반복하여 해커가 복호화 하는 것을 아주 귀찮고 귀찮고 귀찮게 하는 방법입니다. 이런 방법을 통해 복호화는 사실상 불가능하게 만든다고 봐야하지요.

검색을 해보니 요즘 각광받는(?) 암호화 방법에 pbkdf, scrypt, bcrypt 이 세가지 방법이 있어요.
pbkdf 방식 보다는 scrypt방식이 더 안전하다고 합니다. 하지만 알고리즘이 복잡한 만큼 해시와 이터레이션에 사용되는 시간이 더 오래 걸리겠죠? 어떤 방식을 서비스에 더 적절할 지는 개발자의 판단!(하는거 맞죠..? 저도 잘 몰라서)

이번 포스팅에는 pbkdf를 사용하도록 하겠습니다. 

     crypto.pbkdf2(string, buffer.toString('base64'), 130495, 64, 'sha512', function(err, hashed) {
            if(err){
              console.log(err);
            } else{
              console.log(hashed.toString('base64'));
            }
          });


pdkdf함수에는 총 다섯가지의 인자가 들어갑니다.

1. 저희가 처음에 해싱하려 했던 문자열(패스워드)가 들어갑니다.

2. 위에서 랜덤바이트 함수를 통해 생성했던 버퍼있죠? 아까 말씀 드렸던것 처럼 base64로의 인코딩을 통해 넣어줍니다.

3. 이터레이션 반복횟수를 지정해 줍니다. 반복횟수가 많아 질수록 복호화하기 어려워지지만 그만큼 시간도 많이 소모됩니다. (네이버 D2페이지 에서는 1초에 5번 정도 비교할 수 있는 반복횟수를 넣어주는게 좋다고 적혀있어요!)

4. digest의 길이를 설정해줍니다.

5. 어떤 암호화 알고리즘을 사용할 것 인가!  저는 sha512 알고리즘을 이용하였습니다.


로그를 찍어보면  이렇게!



정체모를 문자열을 만들어 줍니다.



이상으로 단방향 암호화와 Crypto 모듈에 대한 포스팅을 마치도록 하겠습니다.

시간이 나면 얼른 양방향 암호화에 대한 포스팅도 작성할 예정입니다.



반응형
Comments