| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2025-6428 |
| 영향 소프트웨어 | Firefox for Android |
| 영향 버전 | Firefox for Android 140 미만 |
| CVSS v3.1 | 4.3 (Medium), AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N (CISA ADP) |
| 공개일 | 2025-06-24 |
| 취약점 유형 | CWE-601, 신뢰할 수 없는 사이트로의 URL 리디렉션 |
| Mozilla 버그 | Bug 1970151 |
| 공식 수정 | Firefox 140 |
Firefox for Android의 앱 링크 처리 경로는 외부 앱으로 넘길 URL을 해석할 때, 계층형 URL의
쿼리 매개변수 afl 또는 link를 대체 목적지로 읽었다. 이 값은 URL을 만든 웹사이트가
정하지만, 패치 전에는 원래 URL을 열지 못했을 때만 쓰여야 할 대체 URL인지 구분하지 않고
처리 흐름에 넣었다. 그 결과 사용자가 신뢰하는 도메인의 링크를 선택해도, 그 URL에 포함된
link 값이 다른 사이트를 가리키면 Firefox for Android가 그 값으로 이동할 수 있었다.
Mozilla는 이를 Firefox for Android에만 영향을 주는 피싱 가능성으로 분류했고, Firefox
140에서 수정했다. 이 결함의 핵심은 URL 문자열 안의 필드 이름이 link라는 사실만으로
그 값을 탐색 실패 시의 대체 목적지로 승격한 데 있다. 링크의 표시상 출발지와 실제로 열리는
목적지가 분리되면 사용자는 사이트가 보장하는 이동 경계를 신뢰할 수 없게 된다.
Android에서 웹 링크는 단순히 브라우저 탭 하나를 여는 요청만은 아니다. 브라우저는 URL의
스킴과 Android Intent 정보를 보고, 연결된 앱을 열지, 앱 스토어로 보낼지, 브라우저 안에
남을지를 결정할 수 있다. 이때 앱이 설치돼 있지 않거나 사용자가 외부 앱 열기를 취소하는
경우를 위해 대체 목적지를 지원하는 구현도 있다.
대체 목적지는 정상적인 탐색 대상과 같은 신뢰 수준으로 다루면 안 된다. 일반 웹 URL의 쿼리 문자열은 웹사이트가 임의로 정하는 애플리케이션 데이터다. 반면 앱 링크 처리기가 사용하는 대체 URL은 브라우저의 탐색 제어 흐름을 바꾸므로, 출처와 사용 조건을 별도로 제한해야 한다.
정상적인 앱 링크 처리
사용자 선택 URL
│
▼
앱 링크 처리기 ──▶ 등록된 외부 앱 실행 시도
│ │
│ └─ 성공: 해당 앱으로 전달
│
└─ 실패 또는 취소: 사전에 제한된 대체 처리 또는 원래 URL 유지
여기서 중요한 불변식은 다음과 같다. 외부 앱 실행이 끝나지 않았다는 사실만으로, 원래 URL의
임의 쿼리 값이 새 탐색 목적지가 되어서는 안 된다. 특히 link처럼 보편적인 이름은 추적,
검색, 쇼핑몰 전환 등 수많은 정상 웹사이트가 사용할 수 있으므로, 매개변수 이름 자체는
신뢰 경계가 될 수 없다.
일반적인 HTTPS URL은 스킴, 호스트, 경로, 쿼리로 나뉜다. 쿼리는 서버에 전달할 추가 데이터이며, 브라우저가 보안상 다른 탐색 위치로 해석해야 하는 명령은 아니다.
https://shop.example/products?id=42&link=https://other.example/
\______________________________/ \______________________________/
원래 탐색 대상 사이트가 제공한 쿼리 데이터
정상적인 URL 로더는 위 주소의 호스트인 shop.example로 이동하고, 서버가 id와 link를
어떻게 해석할지는 그 서버의 몫이다. 앱 링크 처리기가 쿼리를 먼저 읽어 other.example로
탐색을 바꾸면, URL 파서와 앱 링크 처리기가 서로 다른 목적지를 선택하게 된다. 이 불일치는
사용자의 클릭 의도와 브라우저가 최종적으로 연 위치 사이에 피싱에 악용될 수 있는 틈을 만든다.
대체 URL 처리는 편의 기능처럼 보이지만 실제로는 탐색 권한을 결정한다. 안전한 설계에서는 다음 세 정보를 구분해야 한다.
- 사용자가 선택한 원래 URL
- 검증된 앱 링크 메타데이터가 제공한 대체 URL
- 일반 웹 URL의 비신뢰 쿼리 값
이들을 모두 문자열로만 보관해 같은 fallbackUrl 필드에 넣으면, 나중의 분기 코드는 값의
출처를 알 수 없다. 따라서 값이 존재한다는 조건만으로 대체 탐색을 허용하게 된다. 이번
수정은 출처를 다시 판별하는 복잡한 규칙을 추가하는 대신, 문제를 일으킨 afl과 link
매개변수 기반의 대체 URL 지원을 제거해 이 혼동을 없앴다.
Mozilla가 공개한 수정 전후 diff에서 AppLinksUseCases는 RedirectData를 만들 때
fallbackUrl = url.getHierarchicalUrl()을 전달했다. getHierarchicalUrl()은 계층형 URL을
Android URI로 변환한 뒤, 먼저 afl 값을, 없으면 link 값을 읽었다. 두 값이 없을 때만
Intent의 browser_fallback_url extra를 읽었다.
val fallback = uri.getQueryParameter("afl")
?: uri.getQueryParameter("link")
return fallback ?: intentExtra("browser_fallback_url")위 코드는 실제 패치 전 코드의 데이터 흐름만 축약한 것이다. link가 존재하면 원래 URL의
호스트와 무관하게 그 값을 대체 URL로 반환한다. Bug 1970151의 공개 논의에서도 보고자는
Firefox Android 139에서 어떤 URL의 link 매개변수 값으로 이동한다고 확인했고, 담당자는
Google Maps 호환 사례를 복구하려던 회귀이며 원래 URL을 불러올 수 없을 때만 link를
사용했어야 했다고 설명했다.
패치 전에는 앱 링크 해석기가 보통의 HTTPS URL과 앱 링크의 대체 정보를 충분히 분리하지 못했다.
┌────────────────────────────────────────────────────────────────┐
│ 패치 전 Firefox for Android 앱 링크 처리 │
├────────────────────────────────────────────────────────────────┤
│ 사용자가 선택한 URL: https://trusted.example/?link=<다른 목적지> │
│ │ │
│ ▼ │
│ AppLinksUseCases가 쿼리의 afl 또는 link 값 추출 │
│ │ │
│ ▼ │
│ RedirectData.fallbackUrl에 저장 │
│ │ │
│ 외부 앱 처리 경로에서 대체 탐색 가능 │
│ ▼ │
│ 최종 목적지가 원래 trusted.example와 달라질 수 있음 │
│ │
│ 깨진 불변식: 일반 URL의 쿼리는 탐색 목적지를 바꾸지 않아야 함 │
└────────────────────────────────────────────────────────────────┘
이 취약점은 원래 사이트가 악성 스크립트를 실행하는 문제가 아니다. 공격자는 자신이 제어하는
link 값을 포함한 URL을 준비해 사용자가 선택하도록 유도할 수 있고, Firefox for Android의
대체 URL 처리기가 그 문자열을 탐색 대상처럼 취급했다. Mozilla와 NVD의 CVSS 벡터가
UI:R로 표시하는 이유도 사용자의 링크 선택이 필요한 이 흐름과 맞닿아 있다.
일반 웹사이트는 link를 다양한 용도로 사용한다. 따라서 앱 링크 처리기가 link라는 이름을
전역 예약어처럼 다루면, 그 사이트가 의도한 데이터와 브라우저의 앱 전환 정책이 충돌한다.
Bug 1970151에는 매개변수 이름을 바꿔 임시로 동작을 피한 웹사이트와, 데스크톱 및 iOS
Firefox에는 재현되지 않았다는 관찰도 남아 있다. 이는 문제가 웹 표준 URL 파서 일반이 아니라
Firefox Android 전용 앱 링크 계층에 있었음을 뒷받침한다.
보안 결과는 기밀성이나 가용성 손상보다 탐색 무결성의 손상이다. 사용자가 특정 조직의 도메인으로 보이는 URL을 클릭했는데 다른 사이트가 열리면, 로그인 페이지나 결제 화면을 가장한 사이트로 유도하는 피싱의 신뢰 비용이 낮아진다. 다만 공개 자료는 실제 악용 사례를 확인하지 않으므로, 이 보고서는 공개된 동작과 Mozilla가 명시한 피싱 가능성까지만 확정한다.
Mozilla의 수정 커밋은
PARAMS_ANDROID_FALLBACK_LINK와 PARAMS_FALLBACK_LINK 상수를 삭제하고,
getHierarchicalUrl() 함수 전체를 제거했다. RedirectData 생성 시에는 더 이상 URL이나
Intent extra에서 대체 URL을 구하지 않고 fallbackUrl = null을 전달한다.
테스트도 함께 바뀌었다. 기존에는 afl, link, browser_fallback_url이 있는 URL에서
대체 URL이 존재한다고 확인했지만, 패치 뒤에는 각각 대체 URL이 없음을 검증한다. 이는 단순히
특정 악성 도메인을 차단한 것이 아니라, 임의 URL 매개변수를 앱 링크 대체 목적지로 승격하는
경로 자체를 닫은 수정이다.
┌───────────────────────────────────────────────────────────────┐
│ 패치 후 Firefox for Android 앱 링크 처리 │
├───────────────────────────────────────────────────────────────┤
│ 사용자가 선택한 URL │
│ │ │
│ ▼ │
│ AppLinksUseCases │
│ │ │
│ ├─ afl/link 쿼리 매개변수 추출 경로 제거 │
│ └─ fallbackUrl = null │
│ │ │
│ ▼ │
│ 외부 앱 전환이 완료되지 않아도 쿼리 값으로 재탐색하지 않음 │
│ │
│ 복구된 불변식: 일반 URL의 쿼리는 대체 탐색 목적지가 아님 │
└───────────────────────────────────────────────────────────────┘
Mozilla 보안 공지는 Firefox 140을 수정 버전으로 지정한다. Firefox for Android 139의 추적
상태는 wontfix였고, 140은 verified로 표시됐다. 따라서 Android 기기에서 Firefox의
버전을 확인하고 140 이상으로 업데이트해야 한다. 조직이 모바일 기기 관리로 브라우저 배포를
통제한다면, APK 또는 관리형 스토어 채널이 실제로 Firefox 140 이상을 제공하는지도 별도로
확인해야 한다.
이 결함은 서버가 링크를 생성하지 않도록 필터링해 완화할 문제가 아니다. 정상 사이트도
link라는 매개변수를 쓸 수 있으므로, 올바른 경계는 브라우저 쪽 앱 링크 처리기에서 일반
쿼리 값을 대체 목적지로 사용하지 않는 것이다.
Bug 1970151에는 Firefox for Android 139에서의 공개 테스트 사례와 동영상이 첨부돼 있다.
이 보고서는 해당 URL이나 첨부물을 실행하지 않았고, 공개 이슈의 관찰 기록과 Firefox 소스
diff만 정적으로 검토했다. 따라서 여기서 확정하는 범위는 afl 및 link 값의 추출, 그 값의
fallbackUrl 전달, 그리고 그 경로를 제거한 패치 관계다.
- Mozilla는 Google Maps 호환을 위한 회귀였다고 밝혔지만, 원래 호환 요구와 그 변경이 Firefox Android에 들어온 전체 설계 배경은 공개 이슈와 수정 diff만으로 완전히 복원할 수 없음
- Firefox 140보다 오래된 각 Android 배포 채널의 실제 설치 비율과 공개 악용 여부는 공식 공지에 포함되지 않아 이 정적 분석에서 확정할 수 없음
일반 URL의 쿼리 값과 앱 링크 전환 메타데이터를 타입 수준에서 분리하려면 어떤 자료형 경계가 적절할까?
대체 URL 편의 기능을 유지해야 한다면, 어떤 출처 검증과 사용자 표시가 탐색 무결성을 보존할까?
- Mozilla Security Advisory MFSA 2025-51: 영향 제품, Firefox 140 수정, Firefox for Android 한정 영향
- Mozilla Bug 1970151: 재현 관찰, 회귀 원인 설명, 수정 검증, 공개 코드 변경 연결
- Firefox 수정 커밋
1600b429548b:afl/link대체 URL 추출 제거와 테스트 변경, Mozilla Public License 2.0 코드 - NVD CVE-2025-6428: CISA ADP CVSS v3.1 벡터와 CWE-601 분류
본문 참고 자료로 충분했다.