정보실

웹학교

정보실

javascript 웹 암호화 API에 대한 실용적인 가이드

본문

클라이언트측 암호화는 제가 한동안 octo에서 구현하고 싶었던 기능입니다. 마침내 그것을 다룰 시간이 되었을 때, 나는 그 주제에 대한 희소한 실제 사례에 놀랐다. 

MDN에 대한 문서는 강력하지만 개별 메소드 API로 많은 이동이 필요합니다. 이 기사가 도움이 필요한 사람들에게 도움이 되기를 바랍니다.


https://dev.to/voraciousdev/a-practical-guide-to-the-web-cryptography-api-4o8n


참고 : Web Cryptography API는 비동기식이므로 간결성을 위해 이 문서에서 async / await 구문을 사용합니다.


SubtleCrypto 


Web Cryptography API는 처음에는 Crypto라는 비표준 인터페이스를 통해 노출되었지만 나중에 SubtleCrypto라는 새 인터페이스를 통해 표준화 되었습니다. 이 기사는 window.crypto.subtle에 노출 된 공개 SubtleCrypto 인터페이스에 초점을 맞출 것입니다.


Encryption 


이 기사의 목적을 위해 대칭 알고리즘을 사용할 것입니다. 공개 키 (비대칭) 전략에는 키 크기에 따라 암호화 할 수 있는 데이터 양에 대한 엄격한 제한이 있습니다. (keyBits / 8)-패딩. 대칭 암호화는 동일한 키를 사용하여 데이터를 암호화하고 해독하며 ​​동일한 제약 조건이 없습니다. 

몇 가지 지원되는 알고리즘이 있지만 권장되는 대칭 알고리즘은 인증 모드에 대한 AES-GCM입니다.


키 생성 


시작하려면 대칭 키를 생성해야 합니다.


// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
const generateKey = async () => {
  return window.crypto.subtle.generateKey({
    name: 'AES-GCM',
    length: 256,
  }, true, ['encrypt', 'decrypt'])
}


데이터 인코딩 


데이터를 암호화하려면 먼저 데이터를 바이트 스트림으로 인코딩해야 합니다. TextEncoder 클래스를 사용하면 매우 간단하게 이 작업을 수행 할 수 있습니다. 이 작은 유틸리티는 나중에 암호화 기능에서 사용됩니다.


// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
const encode = (data) => {
  const encoder = new TextEncoder()

  return encoder.encode(data)
}


초기화 벡터 (IV) 생성 


간단히 말해 IV는 암호화 전략에 진정한 무작위성을 도입하는 것입니다. 동일한 키를 사용하여 여러 데이터 세트를 암호화하는 경우 암호화 된 암호 청크 간의 관계를 유도하여 원본 메시지의 일부 또는 전체를 노출 할 수 있습니다. IV는 입력 데이터의 반복되는 문자 시퀀스가 ​​결과 암호에서 다양한 바이트 시퀀스를 생성하도록 합니다. IV를 암호화 된 메시지와 함께 일반 텍스트로 저장하는 것은 완벽하게 안전하며 나중에 메시지를 해독하려면 이 작업을 수행해야 합니다.


// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
const generateIv = () => {
  // https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams
  return window.crypto.getRandomValues(new Uint8Array(12))
}


주어진 키에 동일한 IV를 사용하고 싶지 않으므로 나중에 수행 할 암호화 전략에 자동 IV 생성을 통합하는 것이 가장 좋습니다.


데이터 암호화 


이제 모든 유틸리티가 준비되었으므로 암호화 기능을 구현할 수 있습니다! 위에서 언급 했듯이 나중에 암호를 해독 할 수 있도록 암호와 IV를 모두 반환하는 데 필요합니다.


// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt
const encrypt = async (data, key) => {
  const encoded = encode(data)
  const iv = generateIv()
  const cipher = await window.crypto.subtle.encrypt({
    name: 'AES-GCM',
    iv: iv,
  }, key, encoded)

  return {
    cipher,
    iv,
  }
}


전송 및 보관 


대부분의 실질적인 암호화 응용은 암호화 된 데이터의 전송 또는 저장을 포함합니다. SubtleCrypto를 사용하여 데이터를 암호화하면 결과 암호 및 IV가 원시 바이너리 데이터 버퍼로 표시됩니다. 

이것은 전송 또는 보관에 이상적인 형식이 아니므로 다음에 포장 및 포장 풀기를 다룰 것입니다.


데이터 포장 


데이터는 종종 JSON으로 전송되고 데이터베이스에 저장되므로 이식 가능한 형식으로 데이터를 압축하는 것이 좋습니다. 바이너리 데이터 버퍼를 base64로 인코딩 된 문자열로 변환 할 것입니다. 사용 사례에 따라 base64 인코딩은 절대적으로 선택 사항이지만 필요한 만큼 데이터를 이식 할 수 있도록 도와줍니다.


// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
const pack = (buffer) => {
  return window.btoa(
    String.fromCharCode.apply(null, new Uint8Array(buffer))
  )
}



데이터 압축 풀기 


패킹 된 데이터가 전송, 저장 및 나중에 검색되면 프로세스를 되돌리면 됩니다. base64로 인코딩 된 문자열을 원시 바이너리 버퍼로 다시 변환합니다.


// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
const unpack = (packed) => {
  const string = window.atob(packed)
  const buffer = new ArrayBuffer(string.length)
  const bufferView = new Uint8Array(buffer)

  for (let i = 0; i < string.length; i++) {
    bufferView[i] = string.charCodeAt(i)
  }

  return buffer
}


복호화(Decryption) 


우리는 홈 스트레치입니다! 프로세스의 마지막 단계는 달콤한 비밀을 보기 위해 데이터를 해독하는 것입니다. 압축을 풀 때와 마찬가지로 암호화 과정을 반대로 하면 됩니다.


데이터 디코딩(Decoding Data) 


암호를 해독 한 후 결과 바이트 스트림을 원래 형식으로 다시 디코딩 해야 합니다. TextDecoder 클래스로 이를 달성할 수 있습니다. 이 유틸리티는 나중에 해독 기능에서 사용됩니다.


// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
const decode = (bytestream) => {
  const decoder = new TextDecoder()

  return decoder.decode(bytestream)
}


데이터 해독(Decrypting Data) 


이제 해독 기능을 구현하면 됩니다. 앞에서 언급 했듯이 키 뿐만 아니라 암호화 단계에서 사용 된 IV도 제공해야 합니다.


// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt
const decrypt = async (cipher, key, iv) => {
  const encoded = await window.crypto.subtle.decrypt({
    name: 'AES-GCM',
    iv: iv,
  }, key, cipher)

  return decode(encoded)
}


실천에 옮기기 


앱을 작성합시다! 이제 모든 유틸리티가 빌드되었으므로 이를 사용하기 만하면 됩니다. 우리는 데이터를 암호화, 포장 및 보안 엔드 포인트로 전송합니다. 그런 다음 원본 메시지를 검색하고 압축을 풀고 해독합니다.


const app = async () => {
  // encrypt message
  const first = 'Hello, World!'
  const key = await generateKey()
  const { cipher, iv } = await encrypt(first, key)

  // pack and transmit
  await fetch('/secure-api', {
    method: 'POST',
    body: JSON.stringify({
      cipher: pack(cipher),
      iv: pack(iv),
    }),
  })

  // retrieve
  const response = await fetch('/secure-api').then(res => res.json())

  // unpack and decrypt message
  const final = await decrypt(unpack(response.cipher), key, unpack(response.iv))
  console.log(final) // logs 'Hello, World!'
}


그게 전부입니다! 클라이언트 측 암호화를 성공적으로 구현했습니다.


마지막으로 개발자 용 메모 앱 옥토를 한 번 더 공유하고 싶습니다. 

그것은 무료이고 오픈 소스이며 당신이 그것을 확인한다면 절대적으로 좋아할 것입니다. 감사합니다. 즐거운 코딩입니다. ✌️



페이지 정보

조회 6회 ]  작성일20-09-12 17:08

웹학교