심층 분석

EXIF 메타데이터: 사진 속 프라이버시 유출에 대한 기술 가이드

koboshiCo-founder
·9분 읽기
EXIF 메타데이터: 사진 속 프라이버시 유출에 대한 기술 가이드
요약

휴대폰이나 카메라료 찍은 사진에는 모두 그 안에 두 번째 파일이 들어 있다: 촬영 설정, 타임스탬프, 일련번호, 그리고 종종 GPS 좌표다. EXIF의 바이트 수준 구조, 확인하는 방법, 당신을 노출하는 경로, 그리고 형식 변환이 이를 지워 주는 원리를 설명한다.

iPhone으로 사진을 찍고 그 JPEG을 16진수 편집기로 열어 보라. FF D8 시작 마커에서 수백 바이트쯤 지나면 이런 바이트가 보인다:

FF E1 1C 24 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08

FF E1은 APP1 세그먼트 마커다. 그 뒤 두 바이트는 세그먼트 길이다. 이어지는 여섯 바이트는 Exif\0\0이라는 서명이고, 그 바로 뒤에는 TIFF 헤더가 놓여 있다(4D 4D 00 2A는 빅엔디안이라는 뜻이다). 즉 JPEG 안에는 더 작은 두 번째 파일이 들어 있는 셈이고, 그 파일은 종종 이미지 자체보다 당신에 대해 더 많은 것을 드러낸다.

EXIF은 실제로 무엇인가

EXIF은 Exchangeable Image File Format의 약자다. JEIDA(Japan Electronic Industry Development Association)가 1995년에 버전 1.0을 발표했다. 오늘날 표준은 JEITA와 CIPA가 관리하고 있으며, EXIF 3.0은 2023년에 나왔다.

구조적으로 EXIF은 TIFF다. Exif\0\0 헤더 뒤에는 바이트 순서 마커가 오고, 그 뒤로 IFD(Image File Directory)의 체인이 이어진다. 모든 IFD 엔트리는 12바이트다:

Bytes 0-1:   Tag ID (e.g. 0x010F = Make)
Bytes 2-3:   Data type (ASCII, rational, short, long)
Bytes 4-7:   Value count
Bytes 8-11:  Inline value, or an offset to it

프라이버시와 관련된 서브디렉터리는 두 개다. 태그 0x8769가 가리키는 EXIF SubIFD에는 카메라 설정, 일련번호, 타임스탬프가 들어 있다. GPS IFD(태그 0x8825)는 위도와 경도를 각각 세 개의 유리수로 저장한다: 도, 분, 초.

IFD1에는 보통 썸네일, 즉 메타데이터 안에 내장된 작은 JPEG도 저장되어 있다. 이 점은 기억해 두라. 뒤에서 중요해진다.

EXIF를 담는 컨테이너는 다음과 같다:

형식EXIF 위치비고
JPEGAPP1 세그먼트EXIF이 시작된 곳
HEICmeta box의 Exif 항목iOS 11 이후 iPhone 기본값
WebPVP8X 내부의 EXIF 청크선택 사항, 없는 경우도 많다
PNGeXIf 청크2017년에 스펙에 추가됨
TIFF파일 자체가 TIFFEXIF의 부모 형식
BMP/ICO미지원메타데이터 구조가 아예 없다

카메라가 EXIF를 기록하기 시작한 이유

1990년대 중반의 문제는 평범하고 실용적이었다. 디지털 카메라는 아무런 맥락도 없는 파일을 만들어 냈다. 필름 사진가에게는 네거티브 필름과 현상 날짜가 적힌 현상소 봉투, 메모가 있었다. 디지털 사용자에게는 DSC_0042.JPG 같은 파일만 가득한 디렉터리가 있을 뿐이었다.

EXIF은 세 가지 구체적인 필요를 해결했다:

  • 노출 기록. 조리개, 셔터 속도, ISO, 초점 거리를 남겨 두면, 사진가가 어떤 컷이 왜 잘 나왔는지 되짚어 보고 다시 재현할 수 있다.
  • 인화 주문. DPOF(Digital Print Order Format)를 이용하면 카메라에서 인화할 사진을 골라 두고 나중에 키오스크에서 출력할 수 있었다. 회전 같은 EXIF 필드가 여기에 쓰였다.
  • 방향과 미리보기. Orientation 태그 덕분에 세로로 찍은 사진이 바르게 표시되고, 내장 썸네일 덕분에 카메라 LCD에서 사진을 빠르게 넘겨 볼 수 있었다.

여기에 깔린 전제를 짚고 넘어가자. 사진은 소유자 곁에 머무른다는 것이다. EXIF은 사진이 CF 카드에서 하드 드라이브로, 다시 인화 키오스크로 옮겨 다니던 세상을 전제로 설계되었다. 1995년의 JEIDA에서 하루에 열두 장씩 사진을 공개 서버에 올리는 세상을 상상한 사람은 없었다.

실제로 무엇이 들어 있는가

메타데이터 리더로 휴대폰 사진을 하나 열어 보면 태그 목록이 꽤 길게 나온다. 프라이버시 관점에서 의미 있는 필드는 다음과 같다:

태그값 예시드러나는 것
Make / ModelApple, iPhone 15 Pro사용 중인 하드웨어
BodySerialNumber / LensSerialNumber기기마다 고유카메라의 지문
DateTimeOriginal + OffsetTime2026:06:30 18:42:11 +09:00초 단위의 촬영 시각
GPSLatitude / GPSLongitude37°46'29" N, 122°25'10" W수 미터 오차 이내의 위치
GPSAltitude14.2 m대략적인 층수
SoftwareInstagram, Photoshop 26.1파일을 거쳐 간 소프트웨어
Artist / Copyright자유 텍스트때로는 실명
IFD1 썸네일또 하나의 JPEG편집 전 원본 이미지의 복사본

실제 iPhone으로 찍은 사진의 exiftool 출력으로, 보기 쉽게 분량을 줄인 것이다:

$ exiftool IMG_4021.HEIC
Make                            : Apple
Camera Model Name               : iPhone 15 Pro
Serial Number                   : F2LX8A1BCD
Date/Time Original              : 2026:06:30 18:42:11
GPS Latitude                    : 37 deg 46' 29.28" N
GPS Longitude                   : 122 deg 25' 10.41" W
GPS Altitude                    : 14.2 m Above Sea Level

30초만 들여다보면 낯선 사람도 당신이 어떤 카메라료 찍는지, 언제 거기 있었는지, 그리고 그 '거기'가 어디인지를 몇 미터 오차 이내로 알 수 있다.

내 컴퓨터에서 확인하는 방법

Windows

파일을 마우스 오른쪽 버튼으로 클릭해 '속성'을 열고 '자세히' 탭으로 이동한다. 제조사, 모델, 날짜, GPS 좌표가 모두 이곳에 나열된다. 같은 탭 하단의 '속성 및 개인 정보 제거' 링크를 누르면 간단한 메타데이터 제거 대화 상자가 열린다.

PowerShell에서 원시 데이터에 접근하려면:

Add-Type -AssemblyName System.Drawing
$img = [System.Drawing.Image]::FromFile("C:\photos\IMG_4021.jpg")
$img.PropertyItems | ForEach-Object {
    $text = [System.Text.Encoding]::ASCII.GetString($_.Value).Trim([char]0)
    "Tag 0x{0:X4} (len {1}): {2}" -f $_.Id, $_.Len, $text
}
$img.Dispose()

숫자 필드는 원시 바이트로 출력되지만, Make나 Software 같은 ASCII 태그는 깔끔하게 출력된다.

macOS

미리보기에서 이미지를 연 다음 도구 메뉴의 '인스펙터 보기'를 열어 EXIF 탭과 GPS 탭을 확인한다. GPS 탭에는 지도 핀까지 표시된다.

터미널에서 mdls를 실행하면 Spotlight가 인덱싱해 둔 정보가 모두 나온다:

mdls IMG_4021.jpg | grep -iE "gps|latitude|longitude|model"

또는 brew install exiftool로 ExifTool을 설치하면 전체 태그 목록을 볼 수 있다.

Linux

ExifTool이 표준이다:

exiftool IMG_4021.jpg

더 가벼운 대안: exiv2 IMG_4021.jpg, 또는 ImageMagick의 identify -verbose IMG_4021.jpg | grep -i exif.

TypeScript 스무 줄로 브라우저에서 읽기

APP1 세그먼트를 직접 찾으려면 JPEG 마커 체인을 순회하는 루프가 필요하다:

async function findExifSegment(file: File): Promise<number> {
  const bytes = new Uint8Array(await file.slice(0, 128 * 1024).arrayBuffer())
  if (bytes[0] !== 0xff || bytes[1] !== 0xd8) return -1 // not a JPEG

  let offset = 2
  while (offset < bytes.length - 12) {
    if (bytes[offset] !== 0xff) break
    const marker = bytes[offset + 1]
    const length = (bytes[offset + 2] << 8) | bytes[offset + 3]
    if (
      marker === 0xe1 &&
      String.fromCharCode(...bytes.slice(offset + 4, offset + 10)) ===
        "Exif\0\0"
    ) {
      return offset
    }
    offset += 2 + length
  }
  return -1
}

EXIF이 프라이버시를 유출하는 방식

GPS 좌표가 위치를 드러낸다

카메라 앱에 위치 권한이 허용되어 있으면 휴대폰은 GPS를 기록한다. 이 권한은 대부분의 사람이 한 번 허용해 두고는 잊어버리는 설정이다. 발코니나 책상, 아이의 학교 과제 사진을 포럼이나 마켓플레이스 게시글에 올리는 순간, 당신의 주소가 몇 미터 오차의 정확도로 공개된다.

유명한 사례로 John McAfee가 있다. 2012년 12월, 도주 중이던 그는 과테말라에 숨어 있었다. Vice가 iPhone 4S로 촬영한 그의 사진을 게재했는데, EXIF 데이터에는 GPS 좌표가 통째로 들어 있었다. 누구든 그가 과테말라의 정확히 어느 지점에 있는지 알 수 있었다. 며칠 뒤 그는 과테말라 당국에 붙잡혔다.

일련번호가 계정을 연결한다

BodySerialNumber와 LensSerialNumber는 기기마다 고유하다. 같은 카메라료 찍은 사진을 올린 두 개의 익명 계정은 거의 확실하게 서로 연결될 수 있다. 연구자들이 사진 사이트를 크롤링해 카메라 일련번호별로 이미지를 묶어 낸 것도 바로 이 때문이다. 온라인에서는 신원을 얼마든지 분리할 수 있지만, 카메라는 그런 구분을 하지 않는다.

타임스탬프가 일상을 그려 낸다

DateTimeOriginal에 시간대 오프셋이 붙는다. 타임스탬프 하나만으로는 알 수 있는 것이 별로 없지만, 1년 치 업로드가 모이면 당신이 언제 일어나고, 언제 집을 나서고, 언제 여행하는지가 드러난다.

썸네일이 당신을 드러낸다

IFD1 썸네일은 메타데이터 안에 든 별개의 JPEG이다. 메인 이미지에서 얼굴이나 문서를 잘라 내도 상당수 편집 프로그램은 원본 썸네일을 그대로 두기 때문에, 썸네일을 추출한 사람은 잘리지 않은 사진을 얻는다. 2003년에는 TechTV의 한 진행자가 자신의 사진을 크롭해 올렸다가 독자들이 EXIF 썸네일에서 전체 프레임을 복원해 낸 일이 있었다. 이 교훈이 지금까지 유효한 것은 도구들이 같은 실수를 계속 반복하기 때문이다.

업로드 뒤에도 EXIF이 살아남는 곳

대형 소셜 플랫폼(Facebook, Instagram, X)은 업로드 시점에 이미지에서 EXIF을 제거한다. 나머지는 대부분 그렇지 않다: 이메일 첨부, 포럼 업로드, 마켓플레이스 게시글, 클라우드 드라이브 공유 링크, AirDrop, 그리고 원본 화질 전송으로 설정된 모든 메신저. 파일이 원본 그대로 기기를 떠나면 메타데이터도 함께 딸려 나간다.

형식을 변환하면 어떻게 되는가

사진을 변환한다고 메타데이터가 저절로 지워지는 것은 아니다. 변환기에는 두 가지 종류가 있다:

  1. 메타데이터 복사형. 재인코딩은 하지만 태그를 의도적으로 그대로 옮기는 도구다. ExifTool, ffmpeg, 그리고 '메타데이터 유지'가 기본값인 대부분의 GUI 변환기가 여기 속한다. 이런 도구로 JPEG을 WebP로 변환하면 GPS 좌표가 WebP의 EXIF 청크로 그대로 옮겨간다.
  2. 픽셀 재인코딩형. 원시 픽셀로 디코딩하고 그 픽셀로 완전히 새로운 파일을 인코딩하는 도구다. 메타데이터는 애초에 픽셀의 일부가 아니었으므로 출력에는 이미지 데이터만 담긴다.

수동으로 지우는 것도 어느 쪽이든 명령어 하나면 끝난다:

# ExifTool: wipe every tag, keep the image
exiftool -all= -overwrite_original photo.jpg

# ImageMagick 7: re-encode without metadata
magick photo.jpg -strip photo-clean.jpg

여기서 조심해야 할 것이 하나 있다. 바로 방향(orientation)이다. EXIF Orientation 태그(0x0112)는 뷰어에게 이미지를 돌려서 표시하라고 알려 주는데, 보통 90도 회전이다. 이 회전을 픽셀에 반영하지 않고 태그만 지우면 세로로 찍은 사진이 전부 옆으로 돌아간 채 나온다. 올바른 순서는 방향을 적용해서 디코딩한 다음 메타데이터를 지우는 것이다. 회전을 적용하지 않고 지우기만 하는 도구는 지우지 않는 것만 못하다.

우리 변환기의 EXIF 처리 방식

이 사이트의 모든 변환기는 픽셀 재인코딩형이다. 파이프라인은 전부 동일하다:

  1. 브라우저 안에서 원본 파일을 원시 픽셀로 디코딩한다(HEIC은 libheif의 WebAssembly 빌드, 나머지는 브라우저 내장 디코더).
  2. 디코딩 과정에서 EXIF 방향이 이미 반영된 픽셀을 캔버스에 그린다.
  3. 캔버스를 대상 형식으로 인코딩한다.

출력 파일에는 압축된 픽셀 말고는 아무것도 없다. APP1 세그먼트도, EXIFeXIf 청크도, GPS IFD도, 일련번호도, 내장 썸네일도 없다. 복사할 메타데이터가 메모리에 존재하지 않으므로, 메타데이터를 복사하는 코드 경로 자체가 없다. 게다가 전체 과정이 클라이언트 측에서 실행되기 때문에 파일은 기기를 떠나지 않고, 어떤 서버도 원본을 보지 못한다.

원본 형식을 고르라:

파일을 드롭하고, 변환된 사본을 다운로드해서, 원본 대신 그 파일을 공유하라. 픽셀은 그대로이고 메타데이터는 사라졌다.

요약

  • EXIF이 살아남는 곳(이메일, 포럼, 마켓플레이스, 공유 링크)에 사진을 공유하기 전에 먼저 확인하라. Windows에서는 '속성', macOS에서는 '인스펙터', Linux에서는 exiftool이다.
  • 파일에 GPS 데이터가 들어 있고 그것이 싫다면 변환하라. 위에 링크된 모든 도구는 픽셀만 출력한다.
  • 서로 분리된 신원으로 활동하고 있다면 카메라 일련번호가 그 계정들을 연결할 수 있다. 메타데이터를 지우면 이 문제도 해결된다.
  • 원본은 그대로 두라. EXIF은 내 아카이브 안에서는 정말 유용하다. 깨끗해야 할 것은 공개용 복사본 쪽이다.

더 읽을 블로그 글