Młoda para robi selfie ze smartfonem, podczas gdy młody mężczyzna otwiera butelkę

Atrybut rel=noopener – jak chroni przed atakiem tabnabbing

9 min. czytania

Atrybut rel="noopener" to prosty, ale bardzo ważny mechanizm ochrony przed atakiem reverse tabnabbing, który wykorzystuje sposób działania linków otwieranych w nowej karcie (target="_blank"). Dodanie tego atrybutu odcina nowo otwartą kartę od dostępu do strony, z której została otwarta, eliminując możliwość podmiany jej zawartości w celu phishingu.

Skąd w ogóle problem? Linki w nowej karcie a bezpieczeństwo

W świecie tworzenia stron WWW powszechną praktyką jest otwieranie części linków w nowych kartach za pomocą target="_blank" – np. przy linkach zewnętrznych, do dokumentów PDF czy stron partnerów.

Technicznie wygląda to tak:

<a href="https://example.com" target="_blank">Otwórz w nowej karcie</a>

Dla użytkownika takie zachowanie jest wygodne, ale od strony bezpieczeństwa otwiera drogę do specyficznego ataku socjotechnicznego, znanego jako reverse tabnabbing.

Czym jest tabnabbing / reverse tabnabbing?

Tabnabbing (często precyzyjniej: reverse tabnabbing) to atak, w którym złośliwa strona otwarta w nowej karcie próbuje przejąć kontrolę nad kartą, z której została otwarta.

Typowy scenariusz:

  1. Użytkownik odwiedza Twoją stronę (np. panel logowania do banku lub konta w serwisie).
  2. Na stronie znajduje się link z target="_blank" prowadzący do zewnętrznej domeny.
  3. Użytkownik klika link → otwiera się nowa karta z nową stroną (np. pozornie nieszkodliwy blog, artykuł, zasób).
  4. Ta zewnętrzna strona, korzystając z obiektu window.opener, uzyskuje dostęp do karty „rodzica” – Twojej strony.
  5. Złośliwy skrypt podmienia adres w karcie rodzica (np. na fałszywą stronę logowania łudząco podobną do oryginału).
  6. Użytkownik wraca do pierwotnej karty (np. po przeczytaniu artykułu) i widzi „logowanie do swojego banku” – ale w rzeczywistości trafił na stronę atakującego.

Ponieważ użytkownik wciąż jest w „tej samej” karcie, w której wcześniej naprawdę widział zaufaną stronę, dużo łatwiej go oszukać i skłonić do podania danych logowania.

window.opener – klucz do ataku

Sednem problemu jest obiekt window.opener.

Gdy otwierasz stronę w nowej karcie (target="_blank"), przeglądarka w nowo otwartej karcie ustawia window.opener na obiekt reprezentujący stronę-rodzica (kartę, z której kliknięto link). Dzięki temu nowa karta może odwoływać się do rodzica, np. zmieniając adres URL.

window.opener.location = 'https://fałszywy-serwis.test';

To powoduje zmianę adresu w karcie rodzica. Właśnie ta możliwość modyfikacji window.opener.location jest wykorzystywana w tabnabbingu.

Istotne jest to, że do ataku wystarczy możliwość przekierowania rodzica (zmiana location), a nie pełen dostęp do jego DOM-u, więc przeglądarkowe mechanizmy same-origin policy nie zawsze tutaj pomagają.

Atrybut rel="noopener" – jak działa

rel="noopener" to wartość atrybutu rel w znaczniku <a>, której głównym zadaniem jest odcięcie nowej karty od dostępu do window.opener.

Mówiąc prościej: bez noopener nowa karta ma dostęp do window.opener i może manipulować kartą rodzica; z noopener przeglądarka ustawia window.opener w nowej karcie na null, więc nie da się odwołać do karty rodzica ani jej przejąć.

Kod:

<a href="https://example.com" target="_blank" rel="noopener">Zobacz stronę partnera</a>

W praktyce oznacza to: nowo otwarta strona nie może wywołać window.opener.location = ..., a próba dostępu do window.opener zwróci null lub będzie zablokowana.

rel="noopener" skutecznie eliminuje ryzyko reverse tabnabbingu związanego z daną kombinacją target="_blank" + link do zewnętrznej strony.

rel="noreferrer" a rel="noopener" – czym się różnią?

Często spotkasz zalecenie używania obu wartości naraz: rel="noopener noreferrer".

Działanie: noopener odcina dostęp do window.opener (blokuje możliwość manipulacji kartą rodzica), a noreferrer dodatkowo blokuje przesyłanie nagłówka Referer do strony docelowej – dzięki czemu nie dowie się ona, z jakiego dokładnie adresu przyszedł użytkownik.

Oba atrybuty można łączyć:

<a href="https://example.com" target="_blank" rel="noopener noreferrer">Otwórz w nowej karcie</a>

W praktyce: jeśli zależy Ci wyłącznie na ochronie przed tabnabbingiem, wystarczy rel="noopener"; jeśli dodatkowo chcesz ukryć źródło ruchu (np. z powodów prywatności lub polityki serwisu), stosuj rel="noopener noreferrer".

Przykład ataku i jego zablokowania

Przykład podatnego linku (bez zabezpieczeń)

<a href="https://example.com" target="_blank">Kliknij, aby zobaczyć ofertę</a>

W nowo otwartej karcie złośliwy skrypt może zrobić:

// kod w nowo otwartej karcie
if (window.opener) {
window.opener.location = 'https://fałszywa-strona-logowania.test';
}

Efekt: karta rodzica zostaje przekierowana na stronę atakującego.

Ten sam link z zabezpieczeniem

<a href="https://example.com" target="_blank" rel="noopener">Kliknij, aby zobaczyć ofertę</a>

Teraz w nowej karcie:

console.log(window.opener); // null

Skrypt nie jest w stanie przejąć kontroli nad pierwotną kartą, więc atak tabnabbing nie zadziała.

Stan w nowoczesnych przeglądarkach (aktualizacja OWASP)

Według aktualnych materiałów OWASP, nowoczesne, „evergreenowe” przeglądarki (regularnie aktualizowane) domyślnie traktują linki z target="_blank" jakby miały ustawione rel="noopener".

OWASP podkreśla, że w tych przeglądarkach podatność na reverse tabnabbing nie jest już tak powszechna i krytyczna jak dawniej, bo mechanizm jest automatycznie blokowany. Jednocześnie w oficjalnych wytycznych testowania bezpieczeństwa OWASP nadal zaleca, aby wszystkie linki z target="_blank" miały jawnie ustawione rel="noopener noreferrer".

Oto dlaczego mimo „automatyki” warto wciąż dodawać rel="noopener":

  • dla starszych przeglądarek, które nie mają domyślnego zabezpieczenia,
  • dla czytelności kodu – zespół i audytorzy widzą wprost intencję zabezpieczenia linku,
  • wiele skanerów bezpieczeństwa i wytycznych (np. CWE, OWASP) nadal traktuje brak noopener przy target="_blank" jako problem lub co najmniej „złą praktykę”.

Jak poprawnie stosować rel="noopener" w HTML i JS

HTML – zasada główna

Prosta reguła:

Każdy link z target="_blank" powinien mieć rel="noopener (często razem z noreferrer).

Przykłady:

<!-- Bez ukrywania referera (bez wpływu na analitykę) -->
<a href="https://example.com" target="_blank" rel="noopener">Zewnętrzny artykuł</a>

<!-- Z ukryciem referera (dodatkowa warstwa prywatności) -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">Strona partnera</a>

JavaScript – otwieranie okien / kart

Jeśli otwierasz nowe karty przez window.open, przekaż słowa kluczowe noopener i noreferrer:

const link = 'https://example.com';

// Bezpieczne otwarcie nowej karty
window.open(link, '_blank', 'noopener,noreferrer');

Alternatywnie – zgodnie z zaleceniami CWE – możesz ręcznie wyzerować opener:

const newWindow = window.open(link, '_blank');
if (newWindow) {
newWindow.opener = null; // odcięcie dostępu do rodzica
}

Jak testować podatność na reverse tabnabbing

Zgodnie z wytycznymi OWASP Web Security Testing Guide wykonaj następujące kroki:

  • przejrzyj kod HTML aplikacji,
  • wyszukaj wszystkie linki <a> z target="_blank",
  • sprawdź, czy mają ustawiony rel z wartościami noopener i noreferrer.

Jeżeli link ma target="_blank", ale brak rel="noopener", aplikacja prawdopodobnie jest podatna na reverse tabnabbing (przynajmniej w starszych przeglądarkach).

W narzędziach automatycznych (lintery, skanery bezpieczeństwa, audyty dostępności/SEO) często istnieją gotowe reguły wykrywające target="_blank" bez rel="noopener".

Wpływ noopener i noreferrer na SEO i analitykę

noopener a SEO

Atrybut rel="noopener" nie wpływa bezpośrednio na SEO – nie mówi wyszukiwarce, jak ma traktować link (w przeciwieństwie do nofollow), a jego celem jest zwiększenie bezpieczeństwa przez blokadę dostępu do window.opener. Z perspektywy SEO to atrybut neutralny – możesz i powinieneś spokojnie go używać.

noreferrer a źródła ruchu

Atrybut rel="noreferrer" zapobiega przekazaniu informacji o stronie odsyłającej (brak nagłówka Referer), więc strona docelowa nie zobaczy w statystykach (np. w Google Analytics), że ruch przyszedł z Twojej domeny – będzie traktowany jako „direct” lub nieokreślony.

Z punktu widzenia SEO link nadal jest linkiem i może być indeksowany, natomiast strona docelowa nie zobaczy w analityce źródła ruchu, co może utrudniać raportowanie i analizę kampanii. Z perspektywy analityki, jeśli chcesz przekazywać informację o źródle partnerom lub zespołom analitycznym, rozważ stosowanie wyłącznie rel="noopener", bez noreferrer.

Główne zadanie noopener i noreferrer to bezpieczeństwo i stabilność, a nie bezpośrednie sterowanie rankingiem w wyszukiwarce.

Związek z dostępnością (a11y) – nie tylko bezpieczeństwo

  1. Bezpieczeństwo użytkownika to element dostępności. Strona, którą łatwo wykorzystać jako wektor phishingu, w praktyce obniża dostępność – szczególnie dla osób mniej technicznych. Zastosowanie rel="noopener" zmniejsza to ryzyko.

  2. Ostrożne używanie target="_blank". Z punktu widzenia dostępności (WCAG, UX) otwieranie linków w nowej karcie powinno być używane oszczędnie i wyraźnie komunikowane użytkownikowi. Osoby korzystające z czytników ekranu, klawiatury czy technologii wspomagających mogą mieć trudności z orientacją, gdy niespodziewanie otwiera się nowa karta.

  3. Kompromis. Gdy musisz użyć target="_blank" (np. dokumenty, zasoby zewnętrzne), zastosuj rel="noopener" i poinformuj użytkownika w treści linku lub w atrybucie aria-label, że link otworzy się w nowej karcie.

Dobre praktyki – checklista dla front-endu i devów

Przy projektowaniu i implementacji linków:

  1. Zasada podstawowa – dla każdego target="_blank" dodawaj co najmniej rel="noopener";
  2. Gdy chcesz ukryć źródło ruchu – stosuj rel="noopener noreferrer", mając świadomość wpływu na analitykę i statystyki refererów;
  3. JavaScript – przy window.open używaj parametrów "noopener,noreferrer" lub ręcznie ustawiaj newWindow.opener = null;
  4. Audyty i code review – dodaj regułę w linterze/CI, która blokuje mergowanie kodu z target="_blank" bez rel="noopener";
  5. Dostępność – używaj target="_blank" tylko tam, gdzie ma to realny sens, informuj użytkownika, że link otworzy się w nowej karcie, a dla bezpieczeństwa zawsze dodawaj rel="noopener";
  6. Edukacja zespołu – włącz temat reverse tabnabbing do checklist bezpieczeństwa front-endu, wyjaśnij różnice między noopener, noreferrer i innymi wartościami rel (np. nofollow).

Stosowanie rel="noopener" to jedna z najprostszych zmian, które realnie podnoszą bezpieczeństwo użytkowników – bez wpływu na funkcjonalność i SEO; w nowoczesnym ekosystemie webowym to de facto standard dobrych praktyk przy każdym linku otwierającym się w nowej karcie.