JavaScript Crypto라이브러리와 WebCrypto

코드체인 지갑을 만드는 도중, UI가 멈추는 상황이 발생했습니다. 원인을 찾아보던 중 안전하게 키를 저장하기 위해 사용한 codechain-keystore의 비밀키 암호화 과정이 느리다는 걸 발견하고, 이를 간단한 방법으로 개선했습니다.

Source: pixabay.com

먼저, 저희가 발견했던 문제 상황을 설명해드리겠습니다. codechain-keystore는 코드체인에서 사용하는 비밀키를 관리해주는 라이브러리입니다. 사용자로부터 passphrase를 받아 비밀키를 암호화하여 스토리지(하드 디스크, 메모리, 브라우저의 스토리지)에 저장합니다. 유저로부터 passphrase를 받아 암호화를 했기 때문에, 저장된 파일이 유출 되더라도 passphrase를 알지 못하면 비밀키를 복원할 수 없습니다.

문제는 codechain-keystore가 비밀키를 암호화하는 데 사용했던 PBKDF2 함수에서 발생했습니다. PBKDF2는 brute-force attack을 방지하기 위해 key stretching 이라는 기법을 사용합니다. Key stretching이란 해싱을 반복해 사용자가 간단한 암호를 사용해도 brute-force attack으로 암호를 유추하기 어렵게 만드는 기법을 말합니다. PBKDF2는 해시를 반복적으로 계산하기 때문에 시간이 많이 소요되며, 웹브라우저에서 실행 시 UI를 멈추게 할 수 있습니다. 웹브라우저는 자바스크립트를 싱글 쓰레드로 동작시키기 때문에, 자바스크립트에서 이벤트 루프로 리턴하지 않고 많은 연산을 하면 UI가 멈추게 됩니다. codechain-keystore의 초기 구현에서도 PBKDF2의 해시계산 때문에 지갑의 UI가 잠시 멈추는 문제가 있었습니다.

저희는 이 문제를 해결하기 위해 웹브라우저에서 제공하는 Web Crypto API를 사용하였습니다. Web Crypto API는 W3C에서 정의된 표준으로 지금 사용 중인 브라우저 대부분이 이를 지원합니다.

https://caniuse.com/#feat=cryptography

위 그림에서 알 수 있듯이, 전 세계의 91%의 유저들이 사용하는 브라우저에서 Web Crypto API를 사용할 수 있습니다. 단, SecureContext에서만 사용할 수 있기 때문에(link) localhost나 https로 접속한 사이트에서만 사용 가능합니다. 즉, http로 연결된 사이트에서는 Web Crypto API를 사용할 수 없습니다. 따라서 개발용 서버에 http로 접속하는 경우 WebCrypto를 사용하지 못해 느려질 수 있으니 성능을 점검할 때 주의해야 합니다.

하지만 단순히 모든 상황에서 WebCrypto API를 사용하는 것으로 모든 문제가 해결되지 않습니다. 소수지만 WebCrypto API를 전혀 지원하지 않는 상황일 수도 있고, 브라우저마다 지원하는 알고리즘들이 조금씩 다를 수 있습니다. 따라서 필요한 경우 fallback으로 쓰일 라이브러리가 있어야 하며, 상황에 따라 nodejs 환경에서 동작하는 상황도 고려해야 합니다.

codechain-keystore는 웹 브라우저뿐만 아니라 서버 환경의 nodejs에서도 사용되는 라이브러리이기 때문에 환경에 따라서 다른 crypto 라이브러리를 사용해야 했습니다. 웹브라우저 환경에서는 Web Crypto API를, nodejs 환경에서는 빠른 속도를 낼 수 있는 native라이브러리를 사용해야 합니다. 저희는 이를 위해 crypto-browserify를 사용했습니다. crypto-browserify는 node에서 제공하는 Crypto API의 wrapper로, node가 제공하는 crypto 라이브러리를 웹 브라우저에서 실행할 수 있는 코드로 변경해줍니다. crypto가 제공하는 PBKDF2 함수는 pbkdf2Sync와 pbkdf2 두 가지 있습니다. 이 중 pbkdf2Sync를 사용하면 crypto-browserify가 제공하는 자바스크립트 구현체를 호출하고, pbkdf2를 사용하면 Web Crypto API를 호출합니다. 때문에 nodejs 환경에서는 crypto.pbkdf2와 crypto.pbkdf2Sync의 속도 차이가 없지만, 최신 버전의 브라우저에서는 속도의 차이가 매우 큽니다. 따라서 사용하는 crypto 라이브러리가 브라우저를 위한 Web Crypto API 지원을 하는지 확인하고 사용하는 것이 좋습니다.

블록체인 분야는 분산되어있기 때문에 각 클라이언트가 보안을 신경 써야 합니다. 필연적으로 crypto 라이브러리들을 사용해야 하지만, 모든 웹브라우저에서 빠르게 잘 동작하는 crypto 라이브러리는 없으므로, 자신의 상황에 맞게 여러 라이브러리를 조합해서 사용해야 합니다. 저희의 경험이 다른 블록체인 개발자분들에게 도움이 되길 바랍니다.