JavaScript 암호화 라이브러리: 개발자를 위한 최고의 선택
웹 앱을 위한 최고의 JS 암호화 라이브러리를 비교하세요. tweetnacl에서 libsodium.js까지 프로젝트에 맞는 라이브러리를 찾으세요.
2026년 파일 전송 작업에 최적인 JavaScript 암호화 라이브러리는 넓은 알고리즘 커버리지와 WASM 속도를 제공하는 libsodium.js, 최신 감사를 받은 순수 JS 구현인 @noble/ciphers와 @noble/curves, 작은 번들 크기에 NaCl 호환 프리미티브를 제공하는 tweetnacl, 레거시 호환용(신규 코드는 지양)인 crypto-js, 그리고 지원되는 기능이라면 무엇이든 쓸 수 있는 네이티브 Web Crypto API입니다. 이 가이드는 알고리즘 커버리지, 번들 크기, 감사 이력, 브라우저 대 Node 호환성, 파일 암호화 실제 성능을 기준으로 비교합니다.
라이브러리 비교표
| 라이브러리 | 크기(압축 후) | 백엔드 | 주요 알고리즘 | 감사 여부 | 최신? | |---|---|---|---|---|---| | Web Crypto API | 0 KB (네이티브) | 브라우저 네이티브 | AES-GCM, PBKDF2, RSA, ECDH, HMAC | 예(브라우저 벤더) | 예, ChaCha/Argon2 없음 | | libsodium.js | 200 KB WASM / 400 KB JS | WASM + JS 폴백 | libsodium의 모든 것 | 예(다중) | 예 | | @noble/ciphers | 8 KB | 순수 JS | AES, ChaCha20, Poly1305, GCM-SIV | 예(Cure53 2023) | 예 | | @noble/curves | 35 KB | 순수 JS | Ed25519, X25519, secp256k1, BLS | 예(Trail of Bits, Cure53) | 예 | | tweetnacl | 15 KB | 순수 JS | Curve25519, Ed25519, XSalsa20-Poly1305 | 예(원본 NaCl 감사) | 대부분, ChaCha20 없음 | | crypto-js | 50 KB | 순수 JS | AES-CBC, SHA, HMAC, PBKDF2 | 최근 감사 없음 | 아니오, 2023년 이후 유지보수 중단 | | node:crypto | 0 KB (Node 네이티브) | Node 네이티브(OpenSSL) | 포괄적 | 예(OpenSSL) | 예 |
libsodium.js: 만능 도구
libsodium.js(libsodium의 Emscripten 컴파일 빌드)는 Web Crypto로 부족할 때의 기본 선택입니다. XChaCha20-Poly1305, Ed25519, X25519, Argon2id, BLAKE2b, 스트리밍 AEAD용 crypto_secretstream API를 지원합니다. WASM 빌드는 일반 하드웨어에서 네이티브 libsodium 속도의 약 50~70%로 실행됩니다.
import _sodium from 'libsodium-wrappers';
await _sodium.ready;
const sodium = _sodium;
const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
const chunk = sodium.crypto_secretstream_xchacha20poly1305_push(
state, new Uint8Array([1,2,3]), null,
sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
스트리밍 API는 대용량 파일 전송의 핵심 기능입니다. 5GB 파일을 전체 메모리에 올리지 않고 청크 단위로 암호화할 수 있으며, 각 청크에 인증 태그가 포함되어 손상을 끝에서만이 아니라 청크 단위로 감지합니다.
트레이드오프: 200KB WASM은 적지 않습니다. 암호화가 실제로 필요할 때만 라이브러리가 로드되도록 동적 임포트(await import('libsodium-wrappers'))를 사용하세요. sumo 빌드(모든 알고리즘 포함)는 600KB 이상이므로 별도로 필요하지 않으면 기본 빌드를 사용하세요.
@noble: 소형, 감사 완료, 최신
Paul Miller의 @noble 패밀리(@noble/ciphers, @noble/curves, @noble/hashes)는 순수 JavaScript 암호화의 현재 최고 수준입니다. Cure53(ciphers, 2023)과 Trail of Bits(curves, 2022)의 감사를 받았고, 의존성 없음, 트리 쉐이킹 가능, TypeScript 네이티브입니다.
import { gcm } from '@noble/ciphers/aes';
import { randomBytes } from '@noble/ciphers/webcrypto';
const key = randomBytes(32);
const nonce = randomBytes(12);
const ciphertext = gcm(key, nonce).encrypt(plaintext);
@noble는 WASM을 사용하지 않으므로 번들 영향이 작습니다(ciphers는 8KB). 대량 AES-GCM 처리 성능은 libsodium WASM보다 30~50% 느리지만 대부분의 전송 시나리오에서 충분합니다. 순수 JS 방식으로 브라우저, Node, Deno, Bun, React Native에서 네이티브 모듈 우려 없이 동일하게 작동합니다.
번들 크기가 중요하거나, 트리 쉐이킹 가능한 순수 JS 라이브러리를 원하거나, WASM에 문제가 있는 플랫폼에서 @noble를 사용하세요.
tweetnacl: 미니멀리스트
tweetnacl-js는 Daniel J. Bernstein의 TweetNaCl C 라이브러리를 JavaScript로 포팅했습니다. 압축 후 15KB. Curve25519 키 교환, Ed25519 서명, XSalsa20-Poly1305 인증 암호화를 지원합니다. 원본 NaCl 노력의 일환으로 감사를 받았지만 최근 감사는 없습니다.
import nacl from 'tweetnacl';
const key = nacl.randomBytes(32);
const nonce = nacl.randomBytes(24);
const ciphertext = nacl.secretbox(plaintext, nonce, key);
API는 의도적으로 최소화되어 있습니다. NaCl이 제공하는 것 이상이 필요하다면(예: 비 JS 시스템과의 상호 운용을 위한 AES-GCM) 다른 것을 찾아야 합니다. 순수 NaCl 프로토콜 앱에서는 여전히 합리적인 선택이지만, @noble/ciphers와 @noble/curves 조합이 더 최신 유지보수로 같은 기능을 커버합니다.
crypto-js: 신규 코드에는 사용하지 마세요
crypto-js는 2015년 브라우저 암호화를 지배했습니다. 2026년에는 부담이 됩니다. 마지막으로 의미 있는 릴리즈는 2021년(4.1.1)이었고, 저장소는 사실상 2023년에 보관되었습니다. 기본적으로 비밀번호에서 몇 번의 MD5를 통해 키를 파생하는 안전하지 않은 방식(OpenSSL의 EVP_BytesToKey 스타일)으로 AES-CBC를 사용합니다. CVE-2023-46233은 취약한 PBKDF2 기본값을 지적했습니다.
crypto-js를 사용하는 레거시 코드를 유지보수 중이라면 @noble/ciphers나 Web Crypto로 마이그레이션하는 것이 간단하고 시도할 가치가 있습니다. 2026년에 새로 시작한다면 crypto-js를 완전히 건너뛰세요.
서버 코드용 node:crypto
Node의 내장 crypto 모듈은 OpenSSL을 래핑하며 이 목록에서 가장 넓은 알고리즘 커버리지를 갖습니다. Node 18+에서 require('crypto').webcrypto는 Web Crypto 호환 API를 노출하므로 동형 코드가 서버와 클라이언트에서 작동합니다.
import { createCipheriv, randomBytes } from 'crypto';
const key = randomBytes(32);
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', key, iv);
const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = cipher.getAuthTag();
Web Crypto로 암호화된 파일의 서버 측 복호화에 가장 깔끔한 경로입니다.
실제 파일 암호화 성능
MacBook Air M2에서 100MB 버퍼를 AES-256-GCM으로 암호화한 벤치마크입니다.
- Web Crypto API (Chrome 120): 340ms (하드웨어 가속)
- Web Crypto API (Safari 17): 280ms (Apple Silicon 하드웨어 가속)
- libsodium.js WASM: 420ms
- @noble/ciphers: 1,850ms (순수 JS는 하드웨어 가속 없음)
- tweetnacl (XSalsa20): 1,200ms
- node:crypto: 180ms (네이티브 OpenSSL)
핵심: Web Crypto가 AES-NI를 사용하므로 대용량 파일에서 승리합니다. 순수 JS는 소형 페이로드에는 충분하지만 멀티기가바이트 전송에서 수 초가 추가됩니다. 5GB 업로드에서 Web Crypto와 @noble/ciphers의 암호화 시간 차이는 2분 대 10분이 될 수 있습니다.
비밀번호 해시: Argon2 또는 그에 준하는 것
PBKDF2는 기본이지만 Argon2id가 더 좋습니다. 옵션은 다음과 같습니다.
- argon2-browser: WASM 컴파일 참조 구현, 200KB
- @noble/hashes: 순수 JS Argon2id, 15KB, 느리지만 순수
- libsodium.js:
crypto_pwhash를 통한 Argon2id, 200KB(이미 libsodium을 사용 중이라면 포함됨)
브라우저 컨텍스트에서 비밀번호 파생 암호화 키에는 최소 3회 반복, 64MiB 메모리, 4 병렬성으로 Argon2id를 사용하세요(OWASP 2024 지침).
스택에 맞는 선택 가이드
- AES-GCM 암호화로 단순한 파일 전송을 구축하는 경우: 라이브러리 없이 Web Crypto 직접 사용. HexaTransfer가 이 패턴을 따릅니다.
- ChaCha20-Poly1305나 스트리밍 AEAD가 필요한 경우: libsodium.js.
- WASM이 걱정되거나 제한된 번들러를 사용하는 경우: @noble/ciphers + @noble/curves.
- NaCl 프로토콜 키를 사용하는 경우(예: 암호화 파일 수신용 봉인 박스): crypto-js가 아닌 @noble 또는 libsodium.
- crypto-js에서 마이그레이션하는 경우: 번들 크기가 중요하면 @noble, 그렇지 않으면 libsodium.js.
- 포스트 양자 서명이나 KEM이 필요한 경우: 아직 성숙한 JS 라이브러리 없음. @noble/post-quantum을 확인하세요(2026년 초 기준 프리릴리즈).
감사 및 유지보수 신호 확인
암호화 라이브러리를 채택하기 전 확인 사항입니다.
- 마지막 커밋 날짜(18개월 이상 오래된 것은 위험)
- 공개 감사 보고서(Cure53, Trail of Bits, NCC Group)
- 미해결 보안 이슈에 대한 이슈 트래커
- 의존성 수(적을수록 공격 표면이 작음)
- npm 주간 다운로드 수(높을수록 더 많은 눈이 코드를 봄)
JavaScript 생태계는 공급망 사고(event-stream, ua-parser-js, colors)를 겪었고, 이는 최소 의존성을 보안 속성으로 만들었습니다. 런타임 의존성이 없는 암호화 라이브러리(@noble 패밀리, tweetnacl)는 폴리필과 유틸리티를 가져오는 것보다 엔드투엔드 감사가 쉽습니다.
hexatransfer.com에서 사용해 보세요 — 무료, 계정 불필요, 최대 10GB.
엔드투엔드 암호화로 대용량 파일을 안전하게 전송
엔드투엔드 암호화로 최대 10GB의 파일을 무료로 전송하세요. 계정이 필요하지 않습니다. 업로드 전에 브라우저에서 파일이 암호화되어 다른 사람은 읽을 수 없습니다.
파일 보내기