본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

Nodejs에서의 암/복호화

avatar
yceffort
2020-06-09 · 3분
3min
2020year
KOoriginal
nodejssecurity

Nodejs에서의 암호화와 복호화

만약 같은 텍스트로 암호화를 동일하게 시도했을 때, 암호화된 결과가 동일하게 나온다면 이 암호화는 굉장히 약한 암호화라 볼 수 있다. 강력한 암호화는 매번 암호화를 시도할 때마다 (설령 같은 텍스트라 할지라도) 다른 결과가 나와야 한다.

물론, 어쨌든 암호화 되어 있다는 사실 만으로도 만족할 수도 있다. 그러나 공격자가 암호화된 데이터에 접근했을 때 유사한 패턴을 찾게 된다면 그것으로 패턴을 분석할 수 있게 된다. 공격자가 입력한 텍스트가 동일하게 암호화 되었고, 그 암호화된 텍스트가 DB에서 발견 된다면, 그 텍스트는 추론할 수 있게 되며 더 이상 암호화는 유효하지 않게 된다. 따라서 암호화된 출력이 항상 다르게 하기 위해서는, 임의성 (randomness)을 추가해야 한다.

암호화가 매번 다른 결과를 만들어 주는 것이 Initialize Vector (IV) 초기화 벡터이다. 암호화 알고리즘에 IV를 추가하여 위에서 언급한 임의성을 얹을 수 있고, 이 임의성은 암호화가 매번 다른 결과를 만들수 있도록 도와 준다. 강력한 암호화를 위해서는, 매번 암호화를 시도할 때마다 서로다른 랜덤값을 IV로 제공해야 한다. 이는 암호 해싱의 salt와 유사하다.

단순함을 유지하면서, 암호화된 데이터에 대한 단일 데이터베이스 필드와 값을 사용하기 위해, 암호화전에 IV를 준비하여 암호화된 결과에 맞게 준비한다. 그런 다음, 암호를 해독하기전에, IV를 읽고 이를 키와 함께 사용하면 된다.

'use strict'

const crypto = require('crypto')

const ENCRYPTION_KEY =
  process.env.ENCRYPTION_KEY || 'abcdefghijklmnop'.repeat(2) // Must be 256 bits (32 characters)
const IV_LENGTH = 16 // For AES, this is always 16

function encrypt(text) {
  const iv = crypto.randomBytes(IV_LENGTH)
  const cipher = crypto.createCipheriv(
    'aes-256-cbc',
    Buffer.from(ENCRYPTION_KEY),
    iv,
  )
  const encrypted = cipher.update(text)

  return (
    iv.toString('hex') +
    ':' +
    Buffer.concat([encrypted, cipher.final()]).toString('hex')
  )
}

function decrypt(text) {
  const textParts = text.split(':')
  const iv = Buffer.from(textParts.shift(), 'hex')
  const encryptedText = Buffer.from(textParts.join(':'), 'hex')
  const decipher = crypto.createDecipheriv(
    'aes-256-cbc',
    Buffer.from(ENCRYPTION_KEY),
    iv,
  )
  const decrypted = decipher.update(encryptedText)

  return Buffer.concat([decrypted, decipher.final()]).toString()
}

const text = 'hello my name is yceffort'
const encryptResult = encrypt(text)
console.log('encrypt result:', encryptResult)

const decryptResult = decrypt(encryptResult)
console.log('decrypt result:', decryptResult)
encrypt result: bad1fdcaa253c63bc3c8a5aadb7d8913:97a0a7ab35c84d3e52b56afeb717ad888669c67132cc97f941f7969ec52a1732
decrypt result: hello my name is yceffort

여기의 코드를 참고했다.

IV에 대해서 설명하려면 한도 끝도 없고 내 두뇌 용량도 초과하므로, 자세한 설명은 생략하지만 서도 - 암호화를 할 때 꼭꼭꼭꼮 IV를 쓰도록 하자. 이미 nodejs의 crypto 라이브러리에서는 iv 를 쓰지 않는 코드는 deprecated 되었다.

관련 글

  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#security#ssrf

    OG 스크래핑 서버를 Node.js로 짓는다면 (2): SSRF는 어떻게 뚫리는가

    사용자가 준 URL을 서버가 대신 여는 기능은 SSRF의 교과서적 조건을 명세로 갖고 있다. 화이트리스트를 뚫는 우회 여섯 가지를 먼저 보고, 그것을 막는 방어 원리 다섯 개를 Node에서 실제로 돌려본 기록. 손으로 IPv4-mapped를 벗기면 16진 표기에서 뚫리고, undici의 lookup 훅은 호스트가 IP 리터럴이면 아예 호출되지 않으며, URL.hostname은 IPv6 리터럴의 대괄호를 남긴다. OG 스크래핑 서버 설계 노트 2부작의 마지막 편이다.

    2026-08-22·39분
  • #nodejs#security#javascript

    Node.js vm 모듈의 함정: 샌드박스가 아닌 이유

    집필 중인 Node.js Deep Dive의 5.2장(vm 모듈의 함정) 일부를 미리 공개합니다.

    2026-02-27·25분
  • #nodejs#security

    colors.js와 faker.js 사태가 준 교훈

    다이나믹하게 시작하는 2022년

    2022-01-17·10분
  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#web#scraping

    OG 스크래핑 서버를 Node.js로 짓는다면 (1): 런타임 선택부터 에러율과 지연까지

    링크 미리보기 서버의 "에러율 10%"는 성질이 다른 다섯 종류의 실패가 뭉친 숫자다. 이 워크로드가 왜 I/O 바운드에 저 TPS인지, 런타임 선택이 실제로 갈리는 네 지점은 어디인지 따져본 뒤, User-Agent와 인코딩으로 에러율을 낮추는 일로 넘어간다. Node 내장 TextDecoder는 CP949 확장 문자를 에러 없이 다른 글자로 바꾸고, 스크랩해 온 og:title은 API 응답이 아니라 사용자 입력이다. 캐시 스탬피드와 negative caching, 그리고 "P95 1초 미만"을 캐시 히트율에서 역산해 검증하는 200만 건 시뮬레이션까지 담았다. OG 스크래핑 서버 설계 노트 2부작의 첫 편이다.

    2026-08-22·53분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →