JPEG 위조하기

6 hours ago 1

  • 글쓴이는 Spigot이라는 가짜 웹페이지 계층 구조 생성기를 운영하며, 공격적인 웹 크롤러를 상대로 무작위로 생성된 페이지를 노출함
  • 최근에는 이미지 크롤러가 jpg 이미지를 찾기 위해 사이트를 집중적으로 탐색하는 것을 발견함
  • 실시간 이미지 생성을 최소한의 CPU 자원으로 처리하기 위해, 실제 JPEG 파일의 구조화된 부분만을 모아 템플릿으로 활용하고, 압축된 부분에는 무작위 데이터를 삽입하는 방식을 제안함
  • 실험 결과, 이러한 방식으로 만들어진 JPEG는 오류가 있음에도 대부분의 이미지 뷰어에서 이미지를 표시할 수 있고, 크롤러에게도 충분히 그럴듯하게 보임
  • 이 방식은 서버 자원 소모는 적게, 크롤러에게는 부담을 주며 Spigot의 약 60% 페이지에 적용됨

Spigot과 JPEG 위조의 배경

  • Spigot은 Markov Chain 기반으로 가짜 웹 페이지 계층을 실시간으로 생성하여, 공격적인 웹 크롤러에게 무의미한 데이터를 제공함
  • 몇몇 크롤러는 정체를 감추기 위해 무작위 브라우저 시그니처와 IP를 사용, 봇넷을 통한 불법적 디바이스 남용 가능성 발견
  • 트래픽 분석을 통해 새로운 크롤러인 "ImageSiftBot"이 이미지 수집을 위해 집중적으로 Spigot 페이지를 요청함을 확인함
  • Spigot의 주요 목표는 서버 CPU 사용량 최소화 및 효율적인 동작 유지임

저렴한 이미지 생성 방법의 고민

  • 동적으로 이미지를 생성하는 것은 압축 때문에 CPU 소모가 크므로, 효율적인 방법이 필요함
  • JPEG 파일은 파일 구조(크기, 색상 등)와 압축된 픽셀 데이터 구역으로 구성된다는 점에 착안
  • 여러 JPEG에서 구조화된 헤더 정보만 추출한 뒤, 픽셀 데이터 영역은 랜덤 데이터로 채우는 방식이 고안됨
  • 이렇게 하면 매번 이미지를 압축할 필요 없이 즉석에서 생성 가능, 서버 부담 최소화 실현

JPEG 파일구조와 실제 구현

  • JPEG 파일은 여러 개의 청크(마커와 길이가 있음)로 이뤄짐
  • 헤더/메타정보는 남기고, 압축된 픽셀 데이터 길이만 기록→이 영역에만 난수 데이터 삽입
  • 514개의 JPEG 샘플 활용 시, 전체 헤더 정보와 필요한 구조화 데이터 크기는 약 500KB에 불과해 메모리 부담 미미함
  • 코드 예시: 각 템플릿의 픽셀 데이터 청크에 난수를 채워 넣는 방식으로 이미지 생성

실사용 결과와 오픈소스 공개

  • 실제 이미지 뷰어는 픽셀 구역이 완전 난수이어도 어느 정도 이미지를 표시할 수 있음
  • 웹 크롤러는 오류를 식별하기 어렵고, 데이터 수집 시 비용이 증가하게 됨
  • 1280x960, 200~300KB 사이즈 JPEG 기준 초당 약 900장 생성, 실시간 처리에 무리 없음
  • Spigot 전체 페이지의 60%에 이 방식 적용, URL 기반 난수 시드를 사용해 재요청 시 동일 이미지 반환
  • ImageSiftBot, Meta, AmazonBot, GPTBot 등에서 높은 요청량 관측됨
  • 핵심 목적은 적은 서버 리소스크롤러에게 부담을 주는 것

Huffman 코드와 추가 최적화

  • JPEG의 픽셀 데이터는 Huffman 부호화를 사용해, 완전한 난수 삽입 시 일부 뷰어에서 오류 발생 가능성 존재
  • 간단한 비트 마스킹(0x6D) 기법을 추가해 연속 3개 이상 1이 발생하지 않도록 하여, 잘못된 Huffman 코드 발생 확률 90%→4% 미만으로 낮춤
  • 완전히 유효한 Huffman 스트림을 만들 수도 있으나, 서버 자원과 개발 시간 대비 이점이 미미함

결론

  • Spigot의 가짜 JPEG 생성 방식은, 압도적인 효율로 서버 리소스를 아끼면서도 크롤러에게 혼란과 리소스 낭비를 유도함
  • 관련 코드는 100줄 이하로, GitHub에 공개됨
  • 단순하면서도 창의적인 웹 트래픽 방어・분산 기법임

Read Entire Article