Development
[Web] 브라우저 “탭( Tab )”을 노리는 공격, Tabnabbing
곽진돔
2025. 10. 13. 09:30
정보처리기사 실기를 공부하면서 브라우저 탭(Tab) 관련 보안 용어를 정리했습니다. 실무 경험담이 아니라, 문서/자료를 기반으로 정리한 글입니다.

아래 용어 중에서, 올바른 용어를 고르는 문제였는데, 정답은 Tabnabbing이다. 나머지는 문맥적으로 조합하여 부를 수는 있으나, 실제로 통용되는 정확한 정식 용어는 아닌 것으로 보인다.
문제에 출제된 단어와 문맥상으로 해석한 것은 아래와 같다.
용어 요약
| 용어 | 내용 | 표준성 |
|---|---|---|
| Tabnabbing (Reverse Tabnabbing) |
target="_blank"로 연 탭이 window.opener를 통해 원래 탭을 피싱 페이지로 바꿔치기 |
널리 쓰임 |
| Tabjacking / Tabhijacking | 스크립트/확장프로그램이 탭의 콘텐츠/히스토리/포커스를 가로채거나 바꿔치기 | 혼용 |
| Tabspoofing / Tabphishing | 제목·파비콘·UI·알림 등을 바꿔 다른 사이트처럼 보이게 속임 | 혼용 |
| TabSnooping | 다른 탭의 존재/상태를 간접적으로 추론(BroadcastChannel, SharedWorker 등 악용) | 혼용 |
| Tabshadowing | (비표준 용어) 서비스 워커/브라우저 기능을 악용해 사용자 인지 밖에서 탭/세션을 지속 또는 유사 페이지를 재주입 | 혼용 |
| Tabsmishing | SMS(스미싱)로 유도한 링크가 탭에서 열려 탭 기반 위장과 결합된 피싱 | 혼용 |
표준성: 보안 업계에서 정식/공식 용어로 자리 잡은 건 Tabnabbing(특히 Reverse Tabnabbing)뿐이고, 나머지는 맥락에 따라 의미가 겹치거나 블로그/커뮤니티에서 쓰이는 경우가 많습니다.
1) Tabnabbing / Reverse Tabnabbing
Tabnabbing — 발음·의미
- 발음(IPA): tæbˌnæbɪŋ (탭내빙)
- 어원: tab + nabbing(nab=붙잡다/낚아채다)
- 뜻: 새로 연 탭이 window.opener로 원래 탭을 피싱 페이지로 바꿔치기하는 기법
- `noopener`: 새 탭의 window.opener를 null로 만들어 원래 탭 제어 차단(핵심).
- `noreferrer`: Referer 헤더 미전송(유입경로 비노출).
- 분석 리퍼러가 비어질 수 있음 → 필요 시 Referrer-Policy로 조정.
보강: 서버에 Cross-Origin-Opener-Policy: same-origin 설정 시 창 간 격리 강화.
상황
- 우리 사이트에서 외부 링크를
target="_blank"로 열었다. - 새로 열린 페이지(공격자)가
window.opener.location = 'https://fake-login…'을 실행. - 사용자가 원래 탭으로 돌아왔을 때, 이미 피싱 페이지로 바뀌어 있다.
예방
- 외부 링크는 항상 target="_blank" rel="noopener noreferrer"을 사용한다.
<!-- React/HTML 공통 -->
<a href="https://external.site" target="_blank" rel="noopener noreferrer">Open</a>
React 전역 강제 예:
프레임워크 설정을 강제하고 싶다면 아래와 같이 사용할 수 있다.
// React helper
export function SafeExternalLink(props: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
const { rel, target, ...rest } = props;
return <a target="_blank" rel={rel ? `${rel} noopener noreferrer` : 'noopener noreferrer'} {...rest} />;
}
백엔드에서 보안 헤더로 차단 범위를 확대:
Cross-Origin-Opener-Policy: same-origin(교차 출처 창-그룹 분리 →window.opener영향 축소)Referrer-Policy,Content-Security-Policy도 함께 점검
2) Tabjacking / Tabhijacking
아이디어
- 자바스크립트/확장프로그램/애드웨어가 탭을 가로채거나 강제 전환.
history.replaceState,location.replace,window.name악용, 또는 확장프로그램이 클릭을 하이재킹.
대응
- 확장프로그램 권한 남용 모니터링, CSP 강화, 신뢰 못하는 스크립트 로드 금지.
- 사용자 측면: 수상한 확장프로그램 제거, 브라우저 최신 업데이트.
3) Tabspoofing / Tabphishing
아이디어
- 제목(title)·파비콘(favicon)·알림 텍스트를 바꿔 Gmail/은행처럼 보이게 만들어 탭 전환을 유도, 돌아왔을 때 자격 증명 입력 유도.
대응
- 민감 페이지 진입 시 도메인 확인 UX(주소 표시 강조, TLS 배지),
- 로그인은 WebAuthn/OTP로 강화, 비정상 경로 접근 감지 로깅.
4) TabSnooping
아이디어
- BroadcastChannel/SharedWorker/Storage 이벤트 등을 이용해 다른 탭의 존재/상태를 추론(예: 로그인 여부, 페이지 뷰 카운트).
- 직접 크로스 탭 DOM 접근은 불가하지만, 사이드채널로 개인정보 추론 가능.
대응
- 민감 상태는 SameSite=Lax/Strict 쿠키로만 유지.
- 교차 탭 통신 채널 사용 최소화, Storage 이벤트로 민감 데이터 교환 금지.
- COOP/COEP(문맥 격리)을 고려.
5) Tabshadowing
아이디어(사례적)
- Service Worker나 PWA 설치 흐름을 악용해, 사용자가 탭을 닫은 뒤에도 같은 출처로 접근하면 공격자가 캐싱한 위조 페이지를 우선 제공.
- 또는 “합법처럼 보이는 중간 페이지”를 지속 주입해 탭이 ‘그 사이트’인 것처럼 그림자(Shadow)처럼 따라붙음.
현실 조건
- 서비스 워커는 같은 오리진에서만 동작하므로 도메인 소유/서브도메인 탈취/미스컨피그가 선행되어야 함.
대응
- 불필요한 SW 등록 금지, 등록 범위(scope) 최소화, 무결성 체크.
- 출처 보안: 서브도메인 Takeover 방지,
Strict-Transport-Security(HSTS).
6) Tabsmishing
아이디어
- SMS(스미싱) 링크로 사용자를 브라우저 탭으로 유도 → 탭에서 Tabspoofing/Tabnabbing과 결합.
대응(사용자 교육 + 기술)
- 모바일 브라우저에서 주소 표시줄/인증서 확인을 UX적으로 유도.
- 링크 단축/리디렉션 차단 정책, SMS 필터링.
개발자용 체크리스트
- 외부 링크는 항상
target="_blank" rel="noopener noreferrer" - 로그인/결제 등 민감 플로우에서 도메인 표시/검증 UX
- SameSite 쿠키 적용, 세션 최소 권한, 짧은 수명
COOP: same-origin, 필요시COEP: require-corp로 문맥 격리- CSP로 스크립트 출처 화이트리스트,
strict-dynamic검토 - 서비스 워커: 등록 범위 최소화, 불필요 등록 금지, 오프라인 페이지 검증
- 확장프로그램/서드파티 스크립트 의존 최소화, SRI(Subresource Integrity)
- 이상 로그(갑작스러운 리다이렉트, title/favicon 변경 등) 경고
코드 예시
React 예시(링크 컴포넌트 강제 안전화)
type SafeLinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
external?: boolean;
};
export function SafeLink({ external, rel, target, ...rest }: SafeLinkProps) {
return (
<a
target={external ? '_blank' : target}
rel={external ? (rel ? `${rel} noopener noreferrer` : 'noopener noreferrer') : rel}
{...rest}
/>
);
}
Spring Boot 보안 헤더 예시
@Configuration
public class SecurityHeadersConfig {
@Bean
SecurityFilterChain headers(HttpSecurity http) throws Exception {
http
.headers(h -> h
.contentSecurityPolicy(csp -> csp.policyDirectives(
"default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"))
.referrerPolicy(r -> r.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER))
.xssProtection(x -> x.block(true))
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true).preload(true).maxAgeInSeconds(31536000))
.permissionsPolicy(p -> p.policy("geolocation=(), microphone=()"))
);
return http.build();
}
}
마무리
- Tabnabbing은 즉시 조치가 필요하다.
- 개발 단계에서 링크/리다이렉트/서비스 워커/보안 헤더만 꼼꼼히 잡아도 위험도가 크게 줄어든다.