기초를 넘어서는 Canvas 핑거프린팅: 동일한 두 대의 Chrome이 서로 다른 픽셀을 렌더링하는 이유
같은 Chrome, OS, GPU를 쓰는 두 기기도 서로 다른 canvas 픽셀을 렌더링한다. 렌더링 파이프라인이 비결정적인 이유, 프라이버시용 노이즈 주입이 역효과를 내는 이유, 그리고 canvas가 현대 탐지 스택에서 차지하는 위치.
Canvas 핑거프린팅은 2012년부터 실제 서비스에서 사용되어 왔다. 아이디어는 단순하다. 브라우저에게 2D 콘텐츠를 렌더링하게 하고, 픽셀을 다시 읽어 들여 해시를 낸다. 동일한 명령에 대해서도 기기마다 픽셀이 조금씩 다르게 나오고, 그 차이는 세션이 바뀌어도 기기를 식별할 수 있을 만큼 안정적이다.
여기까지는 잘 알려져 있다. 덜 이해된 부분은 이 기법이 왜 작동하는가, 즉 동일한 하드웨어에서 동일한 소프트웨어 구성으로도 왜 서로 다른 픽셀 출력이 나오는가이다. 답은 GPU 드라이버, 폰트 렌더링, 부동소수점 연산이 교차하는 지점에 있다.
렌더링 파이프라인은 결정적이지 않다
JavaScript가 context.fillText("Cwm fjord bank glyphs vext quiz", 4, 45)를 호출하면, Chrome은 픽셀을 직접 렌더링하지 않는다. 2D 그래픽 라이브러리인 Skia를 위한 명령을 생성하고, Skia는 다시 GPU 가속 백엔드(Windows에서는 보통 ANGLE, macOS에서는 Metal, 컨테이너에서는 소프트웨어 폴백)에 그리기 명령을 내린다.
각 단계마다 작은 구현 차이가 쌓인다.
-
Skia의 폰트 서브시스템이 폰트 패밀리를 선택한다. Arial이 설치되어 있지 않으면 대체 폰트로 넘어가는데, 이 대체 결과는 시스템에 설치된 폰트에 따라 달라진다.
-
선택된 폰트는 요청된 크기로 FreeType(Linux), DirectWrite(Windows), Core Text(macOS)를 통해 렌더링된다. 각 라이브러리는 서로 다른 힌팅 알고리즘을 갖는다.
-
서브픽셀 위치 지정이 적용된다. 바로 여기서 동일한 폰트가 서로 다른 픽셀을 만들어내기 시작한다. 알고리즘이 위치를 소수점 단위 픽셀 오프셋으로 반올림하는데, 그 반올림 규칙이 플랫폼마다 다르다.
-
래스터화된 텍스트가 canvas 위에 합성된다. 하드웨어 가속 시스템에서는 GPU 셰이더로, 폴백 모드에서는 CPU 코드로 블렌딩이 이루어진다.
이 각 단계는 픽셀 값 한두 개 정도의 차이를 만들어낼 수 있다. 개별적으로는 눈에 띄지 않는다. 하지만 모이면 고유해진다.
GPU 드라이버 버전이 핑거프린트를 좌우한다
Intel UHD Graphics 620 칩을 탑재한 두 대의 Windows 11 머신도 GPU 드라이버가 다르면 서로 다른 canvas 출력을 낼 수 있다. Intel은 매년 여러 차례 드라이버 업데이트를 배포하며, 각 업데이트는 서브픽셀 필터링, 감마 보정, 텍스트 안티에일리어싱을 바꿀 수 있다.
이는 canvas 핑거프린트의 안정성이 드라이버 업데이트 빈도에 의해 제한된다는 뜻이다. 그래픽 드라이버를 업그레이드한 사용자는 — 흔히 Windows Update를 통해 조용히 이루어진다 — canvas 핑거프린트가 바뀌는 것을 보게 된다.
탐지 시스템은 canvas 핑거프린트를 단독 식별자가 아니라 여러 신호 중 하나로 취급함으로써 이 문제를 다룬다. canvas가 바뀌어도 다른 신호(TLS 핑거프린트, WebGL 렌더러, 시간대, 설치된 폰트)가 그대로 유지되면, 방문자는 여전히 인식된다.
이모지 렌더링은 금광이다
canvas 핑거프린트에서 가장 식별성이 높은 요소는 텍스트나 도형이 아니라 이모지인 경우가 많다. 이모지 렌더링은 OS와 함께 제공되는 이모지 폰트에 의존한다. Windows의 Segoe UI Emoji, macOS의 Apple Color Emoji, Android의 Noto Color Emoji가 그것이다.
하나의 OS 안에서도 이모지 렌더링은 버전에 따라 달라진다. Windows 10이 무지개 이모지를 렌더링하는 방식은 Windows 11과 다르다. iOS 16의 활짝 웃는 얼굴은 iOS 17과 다른 안티에일리어싱을 갖는다.
현대의 canvas 핑거프린팅 스크립트는 Unicode에 새로 추가된 이모지를 포함한 이모지 시퀀스를 의도적으로 렌더링한다. iPhone Safari를 사용한다고 주장하는 방문자가 iOS 17에 추가된 이모지를 렌더링하지 못한다면, 그는 더 오래된 iOS를 쓰고 있거나 플랫폼에 대해 거짓말을 하고 있는 것이다.
자동화 프레임워크는 독특한 핑거프린트를 만든다
GPU 없이 Docker 컨테이너에서 실행되는 헤드리스 Chrome은 렌더링에 SwiftShader를 사용한다. SwiftShader는 내부적으로는 일관되지만 하드웨어 가속 Chrome과는 뚜렷이 구별되는 canvas 출력을 만들어낸다.
그 시그니처는 알아보기 쉽다. 비정상적으로 깔끔한 안티에일리어싱, 그라디언트 영역의 특정 색상 값, 그리고 알려진 어떤 GPU 드라이버와도 일치하지 않는 텍스트 가장자리다. Linux 컨테이너의 Chrome 124에서 SwiftShader와 일치하는 canvas 핑거프린트는 거의 확실히 자동화다. 실제 사용자는 브라우저를 이런 식으로 실행하지 않는다.
Puppeteer-extra-stealth는 toDataURL()을 가로채 수정된 데이터를 반환함으로써 canvas 출력을 위장하려 한다. 하지만 그 수정은 종종 자체적인 아티팩트를 만들어낸다. 세션 전반에 걸쳐 반복되는 노이즈 패턴이 그것인데, 역설적으로 이는 아무것도 하지 않는 것보다 안티핑거프린팅 시도 자체를 더 탐지하기 쉽게 만든다.
노이즈 주입이 잘 통하지 않는 이유
Brave 같은 프라이버시 중심 브라우저는 추적을 막기 위해 canvas 출력에 노이즈를 주입한다. 픽셀 값에 작은 무작위 변형을 더해, 같은 기기가 세션마다 다른 핑거프린트를 내도록 하는 것이 그 아이디어다.
실제로 노이즈 주입에는 세 가지 문제가 있다.
1. 노이즈 그 자체가 핑거프린트다. 매번 로드할 때마다 canvas 출력이 바뀌지만 다른 신호는 그대로 동일한 방문자는 노이즈를 주입하는 브라우저로 알아볼 수 있다. 그 사실 자체가 식별 정보가 된다.
2. 노이즈 알고리즘은 안정적이다. Brave의 구현은 GPU 렌더링의 자연스러운 편차와 일치하지 않는 특정 노이즈 패턴을 만들어낸다. 탐지 시스템은 노이즈가 주입된 것처럼 보이는 canvas 출력과 자연스러워 보이는 출력을 구별할 수 있다.
3. 정교한 시스템은 샘플을 결합한다. 같은 페이지에서의 여러 번의 렌더링, 혹은 여러 세션에 걸친 렌더링을 평균 낼 수 있다. 노이즈가 작으면 그 평균은 기저의 결정적 핑거프린트로 수렴한다.
Canvas 핑거프린팅이 포착하는 것
명백한 시각적 출력 외에도, canvas 핑거프린팅은 부수 효과로 여러 기기 속성을 추출할 수 있다.
렌더링 시간 — canvas 렌더링에 걸리는 시간은 GPU 성능을 드러낸다. 외장 GPU를 갖춘 4K 데스크톱은 중급 노트북보다 빠르게 렌더링한다.
텍스트 메트릭 — measureText()는 폰트 렌더링에 따라 달라지는 정확한 픽셀 너비를 반환한다. 렌더링 없이도 텍스트 너비를 핑거프린트로 쓸 수 있다.
합성 연산 지원 — 일부 브라우저나 GPU 구성은 확장 합성 모드를 지원한다. 지원 여부를 테스트하면 성능 경계가 드러난다.
필터 효과 — canvas에 적용된 CSS 스타일 필터는 GPU마다 다른 출력을 만들어내며, 특히 블러와 드롭섀도 필터가 그렇다.
Canvas 핑거프린팅이 탐지 스택에서 차지하는 위치
canvas 핑거프린팅만으로는 견고한 식별자가 되지 못한다. 드라이버는 바뀐다. 사용자는 브라우저를 갈아탄다. 프라이버시 중심 사용자층에서는 노이즈 주입이 흔하다.
그 진짜 강점은 교차 검증에 있다. 어떤 세션이 쿠키나 계정 로그인을 근거로 재방문 사용자라고 주장할 때, canvas 핑거프린트는 두 번째 신호로 작동한다. 과거 핑거프린트와 일치하면 그 주장이 확인되고, 불일치하면 계정 탈취나 세션 하이재킹을 표시한다.
봇 탐지에서 canvas 핑거프린팅은 컨테이너 기반 자동화를 잡아내는 데 탁월하다. 실제 사용자는 실제 GPU를 갖고 있다. 실제 GPU는 알아볼 수 있는 렌더링 시그니처를 만들어낸다. SwiftShader처럼, 혹은 어설프게 위장된 canvas처럼 렌더링되는 것은 거의 확실히 봇 범주에 속한다.
2012년의 이 기법이 2026년에도 여전히 통하는 이유는 같다. 렌더링은 환경별로는 결정적이지만 완전히 위장하기란 거의 불가능하다. 숨기려는 모든 시도는 그 시도 자체의 흔적을 남긴다.