Firefox Extension IDs: 나쁜 것과 못생긴 것
Source: Dev.to
위의 링크에 포함된 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 현재는 번역할 본문이 없으므로, 번역이 필요한 부분을 복사해서 알려 주세요.
Source: …
Chrome vs Firefox Extension IDs – Why It Matters for CSRF Protection and Privacy
웹 애플리케이션이 브라우저 확장과 통신하도록 개발한 적이 있다면, Chrome과 Firefox가 확장 식별자를 처리하는 미묘하지만 중요한 차이를 경험했을 가능성이 높습니다. 두 브라우저 모두 개발자가 정적 확장 ID를 지정할 수 있게 하지만, 구현 방식이 달라 보안, 프라이버시, 그리고 사용자·개발자 경험에 실제 문제를 일으킵니다.
이 글에서는 Hister 를 만들면서 발견한 이슈를 살펴봅니다. 단순히 CSRF 방어를 구현하려다 보니 Firefox의 확장 아키텍처 결정에 대한 깊은 탐구로 이어졌습니다.
Source: …
정적 확장 ID
Chrome과 Firefox 모두 확장 개발자가 매니페스트에 정적 확장 ID를 정의하도록 허용합니다. 이 ID는 설치 및 업데이트 전반에 걸쳐 확장의 지속적인 식별자로 작동합니다.
Chrome (및 Chromium 기반 브라우저)
확장 ID 처리는 예상대로 작동합니다:
- 매니페스트에 공개 키를 지정하면 정적 확장 ID가 보장됩니다.
- 브라우저는 이 ID를 일관되게 사용합니다.
- 확장에서 발생하는 모든 네트워크 요청은
OriginHTTP 헤더에 이 ID를 포함합니다. - 서버는 어떤 확장이 요청을 보냈는지 식별할 수 있습니다.
- 이 ID는 모든 확장 설치에서 동일하게 유지됩니다.
예시 – 확장 ID가
cciilamhchpmbdnniabclekddabkifhb인 경우, 모든 설치가 해당 ID를 사용하고, 모든 HTTP 요청은chrome-extension://cciilamhchpmbdnniabclekddabkifhb원본으로 자신을 식별합니다.
Firefox
Firefox도 매니페스트에 정적 확장 ID를 지정하도록 허용합니다. 그러나 설치 시 Firefox는 각 설치마다 고유한 내부 UUID를 생성합니다. 이 UUID—사용자가 지정한 정적 ID가 아니라—가 HTTP 요청의 Origin 헤더에 나타납니다.
표면적으로는 사소한 구현 세부 사항처럼 보이지만, 실제로는 상당한 문제를 야기합니다.
나쁜 점: CSRF 보호 우회
Cross‑Site Request Forgery (CSRF) 보호는 모든 웹 애플리케이션에 있어 기본적인 보안 문제입니다. 기본적인 질문은: 서버에 대한 요청이 정당한 클라이언트 애플리케이션에서 온 것인지, 악성 사이트에서 온 것이 아닌지를 어떻게 보장할 수 있나요?
전통적인 웹‑앱 패턴
- 폼에 삽입된 CSRF 토큰
OriginHTTP‑header 검사SameSite쿠키 속성
브라우저 확장 프로그램은 독특한 과제를 제공합니다. 확장 프로그램 코드는 웹 페이지와 독립적으로 실행되며 동일 출처 정책의 적용을 동일하게 받지 않기 때문에, 기존의 CSRF 방어 메커니즘을 바로 적용할 수 없습니다.
Origin 헤더: 자연스러운 해결책
Origin HTTP 헤더는 바로 이 목적을 위해 설계되었습니다. 브라우저가 교차 출처 요청을 보낼 때, 요청이 어디서 왔는지를 식별하는 Origin 헤더를 포함합니다. 확장 프로그램의 경우, 이 헤더에 확장 프로그램 ID가 들어갑니다.
Chrome 구현
// Express.js example
app.post('/api/add', (req, res) => {
const allowedOrigin = 'chrome-extension://cciilamhchpmbdnniabclekddabkifhb';
if (req.headers.origin !== allowedOrigin) {
return res.status(403).json({ error: 'Invalid origin' });
}
// Process the request…
});이 방법은 안전하고 간단하며 사용자 상호작용이 필요하지 않습니다. 확장 프로그램은 서버에 “인증된” 요청을 보낼 수 있고, 서버는 해당 요청이 악의적인 웹사이트나 악성 확장 프로그램이 아닌 정당한 확장 프로그램에서 온 것인지 확인할 수 있습니다.
Firefox 복잡성
Firefox는 정적 ID 대신 설치마다 고유한 UUID를 사용하기 때문에, 위와 같은 패턴은 적용할 수 없습니다. 특정 Origin을 허용 목록에 추가할 수 없으며, UUID가 무엇이 될지 알 수 없기 때문입니다. 확장 프로그램을 설치하는 각 사용자는 서로 다른 UUID를 갖게 됩니다.
해결 방법: 수동 구성
오늘날 Firefox에서 신뢰할 수 있는 유일한 해결책은 사용자가 공유 비밀을 직접 설정하도록 요구하는 것입니다:
- 사용자가 확장 프로그램을 설치합니다.
- 서버가 비밀 토큰을 생성합니다.
- 사용자가 이 토큰을 확장 프로그램 설정에 복사합니다.
- 확장 프로그램이 모든 요청에 토큰을 포함합니다.
- 서버가
Origin헤더 대신 토큰을 검증합니다.
단점
- 추가 설정 단계가 사용자를 낙담시킵니다.
- 사용자 실수가 발생할 가능성이 높습니다.
- 토큰 관리가 사용자의 책임이 됩니다.
- HTTP 레이어에서 Origin을 검증할 수 있는 능력을 잃게 됩니다.
The Ugly: 개인정보에 대한 영향
CSRF 보호를 우회하는 것이 개발자에게는 나쁜 일이지만, Firefox의 내부 UUID 방식은 사용자 개인정보에 더 심각한 영향을 미칩니다.
내장 추적 메커니즘
내부 UUID는 다음과 같습니다:
- 브라우저 설치당 고유합니다.
- 모든 웹사이트에서 지속됩니다.
- 완전히 피할 수 없습니다 (브라우저를 재설치하지 않으면 비활성화하거나 삭제할 수 없습니다).
비교
| Feature | Tracking Cookies | Firefox Extension Internal UUID |
|---|---|---|
| 설정으로 차단 가능 | ✅ | ❌ |
| 사용자가 삭제 가능 | ✅ | ❌ |
SameSite 정책 적용 | ✅ | ❌ |
| 사용자에게 표시됨 | ✅ | ❌ |
| 프라이버시 도구/시크릿 모드에 영향받음 | ✅ | ❌ |
| 설치당 고유 | ✅ (per cookie) | ✅ (per browser) |
왜 Firefox가 이렇게 했을까?
확정적인 답은 없습니다. Mozilla는 “샌드박싱 및 보안” 이유를 들지만, 두 주장 모두 Origin 헤더에 내부 UUID를 사용하는 것을 완전히 정당화하지는 못합니다.
가능한 이유 1: 보안 격리
아마도 의도는 서로 다른 확장 프로그램 설치 간에 더 나은 격리를 제공하는 것이었을 것입니다. 각 설치가 브라우저 수준에서 고유한 ID를 갖는다면, 악의적인 확장 프로그램이 다른 확장 프로그램을 가장하기가 이론적으로 더 어려워질 수 있습니다.
하지만 이 이점은 의문스럽습니다. 확장 프로그램 ID는 이미 브라우저에 의해 검증됩니다; 악성 확장 프로그램은 브라우저가 Origin 헤더를 제어하기 때문에 다른 확장 프로그램의 ID를 위조할 수 없습니다.
핵심 요약
- Chrome: 정적 확장 ID → 예측 가능한
Origin헤더 → 간단하고 신뢰할 수 있는 CSRF 방어. - Firefox: 설치마다 UUID 생성 → 예측 불가능한
Origin헤더 → 깨진 CSRF 패턴, 수동 토큰 흐름 강제, 숨겨진 추적 벡터 발생.
오늘날 Firefox 확장 프로그램을 지원해야 한다면 다음 중 하나를 선택해야 합니다:
- 수동‑시크릿 워크플로를 수용하거나
Origin헤더에 의존하지 않는 맞춤형 서버‑측 검증 방식을 구현합니다.
Firefox가 동작 방식을 바꿀 때까지, 개발자는 보안‑대‑프라이버시 트레이드‑오프를 저울질하고 Firefox 확장 지원이 추가 UX 마찰과 프라이버시 우려를 감수할 가치가 있는지 판단해야 합니다.
가능한 이유 1: 프라이버시‑바이‑디자인
Firefox는 각 확장 설치마다 무작위 UUID를 생성하고 이를 Origin 헤더에 포함합니다. 이는 서버가 두 요청이 동일한 브라우저 설치에서 온 것인지 알 수 없게 만들어 교차‑설치 추적을 방지합니다.
가능한 이유 2: 레거시 확장 시스템에서의 마이그레이션
Firefox는 레거시 XUL 확장에서 WebExtensions로의 대대적인 전환을 겪었습니다. 내부 UUID 시스템은 레거시 아키텍처에서 물려받은 흔적일 가능성이 있으며, 완전히 재검토되지 않았을 수 있습니다.
가능한 이유 3: 우연한 부작용
이것이 의도적인 설계 결정이 아니라, Firefox 확장 시스템이 설계된 방식의 우연한 부작용일 가능성도 있습니다.
어떤 이유든 현재 동작에는 심각한 결함이 있습니다. Chrome조차도 더 프라이버시를 존중하는 해결책을 제공한다는 점에서 문제의 심각성을 알 수 있습니다.
업데이트 (2026‑02‑16)
보이는 바와 같이 목표는 확장 지문 채취를 방지하는 것이었습니다.
개발자 관점
프라이버시와 로컬‑퍼스트 아키텍처를 우선시하는 자유‑소프트웨어 프로젝트를 구축하는 입장에서, Firefox의 동작은 답답합니다.
사용자에게
- Firefox 사용자는 (수동 설정) 때문에 더 나쁜 경험을 합니다.
- 프라이버시를 내세운 브라우저가 실제로 프라이버시 문제를 일으킵니다.
- 내부 UUID 시스템에 대한 투명성이 없습니다.
개발자에게
Origin헤더를 통한 적절한 CSRF 보호를 구현할 수 없습니다.- UX를 해치는 우회책을 구현해야 합니다.
- 문서가 더 복잡해집니다.
- 테스트가 어려워집니다 (여러 Firefox 설치를 쉽게 시뮬레이션할 수 없음).
Firefox는 무엇을 해야 할까요?
해결책은 간단합니다: Chrome과 마찬가지로 Origin HTTP 헤더에 정적 확장 ID를 사용하십시오.
면책 조항
제가 상당한 시간을 들여 연구하고 이러한 문제들을 해결할 방법을 찾으려 했지만, 제가 완전히 놓친 부분이 있을 수 있으며 언급된 문제 중 하나 또는 두 개 모두에 대한 해결책이 존재할 수도 있습니다. 그런 경우, Mastodon에서 저에게 연락해 주세요: @asciimoo@chaos.social.