이미지 DRM 구현을 위한 커스텀 이미지 포맷

8 days ago

이미지 DRM 구현을 위한 커스텀 컨테이너 접근

이 글에서는 이미지 DRM(Digital Rights Management)을 간단히 구현하기 위한 방법으로, 커스텀 컨테이너 포맷을 사용하는 과정을 살펴봅니다. 일반적인 PNG/JPEG 파일을 그대로 제공하면 네트워크 트래픽을 훔쳐보거나(패킷 스니핑, HTTP 후킹 등) 직접 다운로드해 무단으로 사용하는 경우가 발생할 수 있습니다. 이러한 문제를 방지하기 위해, 이미지를 암호화하여 커스텀 포맷으로 제공하고, 클라이언트(앱, 웹)에서만 복호화해 볼 수 있도록 하는 방식을 소개합니다.

DRM 개념과 필요성


커스텀 컨테이너 포맷 설계

1. 기본 구조

파일(컨테이너) 헤더:
파일 바디:

2. 흐름 요약

  1. 서버
    1. 원본 이미지를 읽음
    2. AES 등으로 암호화
    3. 헤더 + 암호화된 이미지 → 커스텀 컨테이너 `.cimg` 또는 `.enc` 등의 확장자로 제공
  2. 클라이언트
    1. 컨테이너 파일 수신
    2. 헤더 파싱 후, 암호화 방식 확인
    3. 복호화 (비밀 키 필요)
    4. 복호화된 이미지 데이터를 표준 뷰어(UIImage, HTML `<img>` 등)로 디스플레이

서버 측 구현 (Node.js 예시)

컨테이너 포맷

헤더 구조 (예시 총 20바이트)
오프셋길이설명
04매직 넘버 `"CIMG"`
44버전 (정수)
84암호화 방식 (정수)
128예약 (0으로 채움)

암호화/복호화 로직

CLI 도구 예시

아래는 Node.js 환경에서 이미지 파일을 암호화→컨테이너 생성, 복호화→이미지 파일 추출을 수행하는 간단한 예시 코드입니다.
image_container_cli.js (발췌)
js
1#!/usr/bin/env node
2const fs = require('fs');
3const crypto = require('crypto');
4
5// 암호화 방식 식별자
6const EncryptionMethod = {
7 NONE: 0,
8 AES_CBC: 1,
9};
10
11// 이미지 → 컨테이너 (암호화)
12function createContainer({ imagePath, containerPath, encryptionMethod, secretKey }) {
13 const imageData = fs.readFileSync(imagePath);
14 let encryptedData;
15
16 if (encryptionMethod === EncryptionMethod.NONE) {
17 // 암호화 없이 그대로
18 encryptedData = imageData;
19 } else if (encryptionMethod === EncryptionMethod.AES_CBC) {
20 const iv = crypto.randomBytes(16);
21 const cipher = crypto.createCipheriv('aes-256-cbc', secretKey, iv);
22 encryptedData = Buffer.concat([iv, cipher.update(imageData), cipher.final()]);
23 } else {
24 throw new Error('지원하지 않는 암호화 방식');
25 }
26
27 // 헤더 생성 (20바이트)
28 const header = Buffer.alloc(20);
29 header.write('CIMG', 0, 4, 'utf8'); // 매직 넘버
30 header.writeInt32BE(1, 4); // 버전 1
31 header.writeInt32BE(encryptionMethod, 8); // 암호화 방식
32 // 나머지 8바이트는 0 채움
33
34 // 파일 합치기
35 const containerData = Buffer.concat([header, encryptedData]);
36 fs.writeFileSync(containerPath, containerData);
37}
38
39// 컨테이너 → 이미지 (복호화)
40function extractImage({ containerPath, outputImagePath, secretKey }) {
41 const containerData = fs.readFileSync(containerPath);
42
43 // 헤더 읽기
44 const magic = containerData.slice(0, 4).toString('utf8');
45 if (magic !== 'CIMG') throw new Error('유효하지 않은 컨테이너');
46 const encryptionMethod = containerData.readInt32BE(8);
47
48 // 암호화된 데이터
49 let encryptedData = containerData.slice(20);
50 let imageData;
51
52 if (encryptionMethod === EncryptionMethod.NONE) {
53 imageData = encryptedData;
54 } else if (encryptionMethod === EncryptionMethod.AES_CBC) {
55 const iv = encryptedData.slice(0, 16);
56 const actualEncrypted = encryptedData.slice(16);
57 const decipher = crypto.createDecipheriv('aes-256-cbc', secretKey, iv);
58 imageData = Buffer.concat([decipher.update(actualEncrypted), decipher.final()]);
59 } else {
60 throw new Error('지원하지 않는 암호화 방식');
61 }
62
63 fs.writeFileSync(outputImagePath, imageData);
64}
65
66// CLI 로직 (encrypt, decrypt 명령)
67// ... (생략) ...
주의: 실제 사용 시 비밀 키(32바이트)를 안전하게 관리해야 합니다.

클라이언트 측 구현

iOS(Swift) 또는 Android

웹 환경(HTML + JavaScript)

HTML 예시 (요약)
html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="UTF-8" />
5 </head>
6 <body>
7 <input type="file" id="fileInput" />
8 <img id="preview" />
9
10 <script>
11 const KEY_HEX = 'f1e2...'; // 32바이트 Hex
12 // 1) FileReader로 ArrayBuffer 읽기
13 // 2) 헤더 파싱
14 // 3) Web Crypto API로 복호화 (AES-CBC)
15 // 4) Blob -> ObjectURL -> <img>에 표시
16 </script>
17 </body>
18</html>

보안 고려사항

  1. 키 관리:
    • 클라이언트에 키가 노출되지 않도록 주의해야 합니다.
    • 앱 내부에 하드코딩된 키도 역공학에 취약할 수 있으므로, 서버와 안전한 통신으로 키를 교환하거나 토큰을 사용하는 전략이 필요합니다.
  2. 역공학 방지:
    • 모바일 앱이나 웹 브라우저 환경에서, 결국 복호화 로직이 공개되어 있습니다.
    • 난독화(Obfuscation) 또는 각종 안티 디버깅, 루팅/탈옥 탐지 기법을 활용해 공격 난이도를 높일 수 있습니다.
  3. 추가적인 DRM:
    • 화면 캡쳐 방지, 워터마크 삽입, 법적 공지 등의 복합적인 DRM 전략이 필요할 수 있습니다.
  4. 전달 방식 보안:
    • 반드시 HTTPS 통신을 사용하여 네트워크 중간에서 스니핑되지 않도록 방지해야 합니다.
    • 서버 인증(토큰, OAuth 등)을 통해 인증된 사용자만 파일을 가져갈 수 있게 해야 합니다.

마무리

이미지 DRM을 완벽히 구현하기 위해서는 다양한 레이어의 보안 기법이 필요합니다. 여기서는 커스텀 컨테이너 + 암호화 방식을 통해 가장 기초적인 DRM 아이디어를 소개했습니다.
따라서 DRM을 강력히 구현하려면, 애플리케이션 레이어 보안, 서버-클라이언트 인증 흐름, Tee(Trusted Execution Environment) 연동, FairPlay(Apple) / Widevine(Google) 와 같은 상용 DRM 솔루션 등을 종합적으로 고려해야 합니다.
이 문서가 도움이 되셨다면, 댓글이나 피드백을 남겨주세요!
더 궁금한 사항이 있으면 언제든지 문의 바랍니다.

nextjs로 이전 했습니다.