AES 암호화를 활용한 익명 투표

0

프로젝트의 기능 중 하나인 투표를 담당하면서 db에서 추적되지 않는 익명투표를 위해 암호화에 대해 공부하며 기록을 남기게 되었다.

전체적인 프로세스는 다음과 같다.
1️⃣ 투표를 익명으로 생성 시 db에서 추적이 불가능하게 하기 위해 먼저 사용자 id를 해시하고
2️⃣ 이 값의 일부로 고유한 AES키를 생성해 서버에 전달한다.
3️⃣ 이를 해당 투표의 고유 id로 정의하고
4️⃣ 사용자가 투표 답변, 수정, 삭제 시 동일한 방법으로 서버에 고유한 키를 보내면
5️⃣ 서버에 저장되어 있던 암호화된 투표 고유 id와 비교해 자신이 생성한 투표인지 아닌지를 판단할 수 있게 하였다.

따라서 사용자의 원래 id를 서버에 전달하지 않고 db에는 사용자를 식별할 수 있는 정보가 없으므로 익명성이 보장된다.

코드를 살펴보자면

import forge from "node-forge";

function getSignature(publicKey: string, content: string): string {
  const md = forge.md.sha256.create();
  md.update(publicKey);
  const key = md.digest().getBytes(16); // AES-128 사용

먼저 사용자 ID를 해시하여 AES 키를 생성하고

  const iv = "0000000000000000";

동일키에 동일 암호문이 나와야 하기 때문에 IV (초기화 벡터)를 고정시킨다.

const cipher = forge.cipher.createCipher("AES-CBC", key);
cipher.start({ iv: iv });
cipher.update(forge.util.createBuffer(content));
cipher.finish();

const encrypted = cipher.output.getBytes();

forge 라이브러리를 사용하여 AES-CBC 암호화 객체를 생성하고 위에서 만든 AES 키를 설정한다. 이 후 암호화된 데이터를 바이트 배열로 변환하여 저장한다.

 return forge.util.encode64(encrypted);

최종으로 IV와 암호화된 데이터를 Base64로 인코딩하여 반환하는 함수를 만들었다.

이후 테스트를 진행하였는데 url로 이 키를 전달할 시 기호(?*^% 등)가 빈 문자열로 들어가는 이슈로 인해 투표를 생성한 사람과 동일함에도 매칭이 안되는 문제가 생겼다.

url-safe 문자열로 변환하기 위해 encodURIComponent로 한번 감싸서 보내 해결할 수 있었다.

 return encodeURIComponent(forge.util.encode64(encrypted));


➕ 추가로 알게 된 것 ➕

AES는 대칭 키 암호화 방식으로 고정된 키와 초기화 벡터(IV)를 사용해 데이터를 암호화한다.

여기서 대칭키 암호 알고리즘과 비대칭키 암호 알고리즘을 비교하며 좀 더 알아보자면 다음과 같은 특징이 있다.

✔️ 대칭키 암호 알고리즘

  • 하나의 키로 암호화/복호화를 모두 수행하는 알고리즘
  • 암호화하는 암호키와 복호화하는 해독키가 같다.
  • 따라서 이 키는 절대 외부에 노출되면 안되고 해당 키를 Secret Key라고 부른다.
  • 프론트엔드와 백엔드 간의 동일한 키를 공유해야하기 때문에 키 관리에 대한 어려움이 있고, 잦은 키 변경이 있는 경우에는 불편함을 초래할 가능성이 있다.
  • 비대칭키 암호 알고리즘보다 속도가 빠르다.
  • 키가 노출되면 암호화된 데이터를 복호화할 수 있다는 취약성이 있다.

✔️ 비대칭키 암호 알고리즘

- 암호화/복호화 시의 키가 서로 다른 키를 의미한다.

  • 공개키와 개인키를 사용한다.
  • 한 쌍의 키가 존재하며 하나는 특정 사람만이 가지는 개인키이며 하나는 누구나 가질 수 있는 공개키이다.
  • 예를들어 공개키로 암호화한 데이터는 개인키로만 복호화할 수 있고 반대로 개인키로 암호화한 데이터는 공개키로만 복호화할 수 있다.
  • 누군가 공개키를 가로채더라도 개인키를 모르기 때문에 데이터를 온전히 복호화할 수 없다.
  • 주로 키 교환이나 인증에 사용한다.
  • 대칭키 암호 알고리즘에 비해 느리다.


참고

0개의 댓글