본문 바로가기
카테고리 없음

외부 링크 보안 설정 rel="noopener noreferrer" 보안과 SEO 동시에 잡기

by BOOST YOUR INFORMATION 2026. 5. 7.

rel="noopener noreferrer" 속성으로 보안과 참조 이미지
외부 링크 보안 설정: rel="noopener noreferrer" 속성

외부 링크 보안 설정: rel="noopener noreferrer" 속성으로 보안과 SEO 동시에 잡기

외부 링크에 target="_blank"를 쓰면서 rel="noopener noreferrer"를 빠뜨리는 것, 이게 얼마나 위험한 일인지 대부분의 개발자가 모른다. 아니, 알면서도 그냥 넘어간다. 나도 그랬다. 별일 있겠냐 싶었다. 그런데 실제로 해당 취약점을 통한 공격 사례를 접하고 나서 생각이 완전히 바뀌었다. 잠그지 않은 자동차 문에 현금 다발을 올려두는 것과 같은 일이었다.

target="_blank"의 숨겨진 위험: window.opener 취약점

target="_blank"로 외부 링크를 열면 새 탭이 생성된다. 여기까지는 누구나 안다. 그런데 이때 새로 열린 탭은 원래 페이지, 즉 opener 페이지에 대한 참조를 window.opener를 통해 갖게 된다. 이 말은 새로 열린 외부 사이트가 원래 페이지를 제어하거나 리디렉션할 수 있다는 뜻이다.

실제 공격 시나리오는 이렇다. 내 블로그에서 어떤 외부 링크를 target="_blank"로 연결해뒀다고 하자. 그 외부 사이트가 악의적이거나 해킹당한 상태라면, 사용자가 외부 사이트를 보는 동안 window.opener.location을 조작해 원래 페이지, 즉 내 블로그 탭을 피싱 사이트로 바꿔치기할 수 있다. 사용자는 외부 탭을 보다가 돌아왔더니 로그인 화면이 나타나 있는 걸 보게 된다. 자신이 보던 사이트 주소가 그대로이므로 의심 없이 아이디와 비밀번호를 입력한다.

<!-- 위험한 방법: rel 속성 없이 target="_blank" 사용 -->
<a href="https://external-site.com" target="_blank">외부 사이트 방문</a>

<!-- 안전한 방법: rel 속성으로 opener 차단 -->
<a href="https://external-site.com" target="_blank" rel="noopener noreferrer">외부 사이트 방문</a>

noopener와 noreferrer 각각의 역할

두 속성이 하는 일이 다르다. noopener는 새 탭에서 window.opener를 null로 만들어버린다. 새로 열린 페이지가 원래 페이지를 참조하지 못하게 막는 것이다. noreferrer는 여기에 더해 HTTP Referer 헤더도 전송하지 않는다. 즉 외부 사이트에서 방문자가 어디서 왔는지 알 수 없게 된다.

대부분의 경우 두 속성을 함께 쓰는 게 맞다. noopener만 쓰면 Referer는 여전히 전송된다. noreferrer만 쓰면 브라우저 호환성 문제가 생길 수 있다. 특히 오래된 브라우저에서 noreferrer가 noopener의 역할을 겸하는 경우가 있어서 함께 쓰면 안전하다.

<!-- 외부 링크 완전한 보안 처리 예시 -->
<a
  href="https://www.google.com"
  target="_blank"
  rel="noopener noreferrer"
  aria-label="Google 검색 (새 탭에서 열림)"
>
  Google에서 검색하기
</a>

aria-label에 "(새 탭에서 열림)"을 명시하는 것도 접근성 측면에서 중요하다. 스크린 리더 사용자가 새 탭이 열린다는 사실을 미리 알 수 있도록 알려주는 것이다. 보안, 접근성, SEO를 동시에 고려하는 방식이다.

SEO에 미치는 영향: 링크 주스와 rel 속성

SEO 관점에서 rel 속성은 단순 보안 이슈를 넘어선다. 구글은 링크를 통해 페이지 간 신뢰도와 권위를 전달하는 개념인 링크 주스를 분석한다. 외부 링크에 rel 속성이 없으면 구글이 이 링크를 일반적인 do-follow 링크로 처리한다. 즉 내 사이트의 신뢰도를 외부 사이트로 전달하는 셈이 된다.

rel="noreferrer"는 nofollow와는 다르다. noreferrer는 Referer 헤더를 차단하는 것이고, nofollow는 크롤러에게 이 링크를 따라가지 말라고 신호를 보내는 것이다. 만약 외부 링크가 광고이거나 신뢰할 수 없는 사이트라면 rel="nofollow"도 함께 추가해야 한다.

<!-- 일반 외부 링크: noopener noreferrer -->
<a href="https://trusted-site.com" target="_blank" rel="noopener noreferrer">
  신뢰할 수 있는 외부 사이트
</a>

<!-- 광고 또는 유료 링크: nofollow 추가 -->
<a href="https://advertiser-site.com" target="_blank" rel="noopener noreferrer nofollow">
  광고 파트너 사이트
</a>

<!-- UGC(사용자 생성 콘텐츠) 링크: ugc 속성 사용 -->
<a href="https://user-posted-link.com" target="_blank" rel="noopener noreferrer ugc">
  사용자가 남긴 링크
</a>

JavaScript로 동적 링크에 적용하는 방법

CMS나 동적으로 생성되는 콘텐츠에서 링크가 자동 생성될 때 rel 속성을 빠뜨리는 경우가 많다. 이럴 때는 JavaScript로 일괄 처리하는 방법이 현실적이다.

// 페이지 내 모든 외부 링크에 자동으로 보안 속성 추가
document.addEventListener('DOMContentLoaded', function() {
  var links = document.querySelectorAll('a[href]');

  links.forEach(function(link) {
    var href = link.getAttribute('href');

    // 외부 링크인지 확인 (http로 시작하고 현재 도메인이 아닌 경우)
    if (href && href.startsWith('http') && !href.includes(window.location.hostname)) {

      // target="_blank" 추가
      link.setAttribute('target', '_blank');

      // rel 속성 처리: 기존 rel 값 유지하면서 추가
      var existingRel = link.getAttribute('rel') || '';
      var relValues = existingRel.split(' ').filter(Boolean);

      if (!relValues.includes('noopener')) {
        relValues.push('noopener');
      }
      if (!relValues.includes('noreferrer')) {
        relValues.push('noreferrer');
      }

      link.setAttribute('rel', relValues.join(' '));
    }
  });
});

WordPress나 CMS에서 일괄 적용하는 방법

워드프레스를 쓴다면 functions.php에 필터를 추가해 모든 콘텐츠 링크에 자동 적용할 수 있다. 이 방법이 게시물마다 수동으로 처리하는 것보다 훨씬 효율적이다.

<?php
// WordPress functions.php에 추가
function add_noopener_to_external_links($content) {
    // 외부 링크를 찾아서 rel 속성 추가
    $pattern = '/<a\s[^>]*href=["\']https?:\/\/(?!' 
    . preg_quote($_SERVER['HTTP_HOST'], '/') . ') [^"\']*["\'][^>]*>/i';

    $content = preg_replace_callback($pattern, function($matches) {
        $tag = $matches[0];

        // target="_blank" 없으면 추가
        if (strpos($tag, 'target=') === false) {
            $tag = str_replace('<a ', '<a target="_blank" ', $tag);
        }

        // rel 속성 처리
        if (strpos($tag, 'rel=') === false) {
            $tag = str_replace('<a ', '<a rel="noopener noreferrer" ', $tag);
        } else {
            // 기존 rel 속성에 값 추가
            $tag = preg_replace('/rel=["\']([^"\']*)["\']/', 
                      'rel="$1 noopener noreferrer"', $tag);
        }

        return $tag;
    }, $content);

    return $content;
}
add_filter('the_content', 'add_noopener_to_external_links');
?>

현장에서 느낀 장단점

장점은 명확하다. 보안 취약점 하나를 간단하게 막을 수 있고, SEO 링크 구조도 명확해진다. 코드 한 줄 추가로 얻는 효과치고는 손익 비율이 압도적으로 좋다. 구글 Search Console에서 외부 링크 품질 평가도 개선된다.

단점은 Analytics 트래픽 추적이 달라질 수 있다는 점이다. noreferrer를 쓰면 외부 사이트로 넘어갈 때 Referer 헤더가 없어서, 내 사이트에서 해당 외부 사이트로 얼마나 트래픽을 보냈는지 그쪽 Analytics에서 직접 확인이 어려워진다. 파트너 사이트와 트래픽 공유를 해야 하는 경우라면 UTM 파라미터를 URL에 직접 추가하는 방식으로 대응해야 한다.

마무리: 링크 하나에도 책임이 있다

개발을 오래 하다 보면 사소한 것들이 실은 사소하지 않다는 걸 알게 된다. target="_blank" 하나에도 보안 설계가 들어가야 하고, 외부 링크 하나에도 SEO 전략이 담겨야 한다. rel="noopener noreferrer"는 그냥 속성 두 개가 아니라, 내 사이트를 방문하는 사람들을 보호하겠다는 의지의 표현이다. 마치 집 문을 잠그는 게 귀찮더라도 하는 이유와 같다.

현장에서 수년간 코드 리뷰를 하면서 이 속성이 빠진 링크를 수도 없이 발견했다. 그때마다 왜 빠뜨렸냐고 물으면 대부분 몰랐거나 귀찮았다는 대답이 돌아왔다. 이 글을 읽는 분이라면 이제 몰라서는 아닐 것이고, 귀찮음이라는 핑계도 코드 한 줄이면 해결된다. 외부 링크를 달 때 target="_blank"를 쓴다면 반드시 rel="noopener noreferrer"를 함께 쓰는 습관을 들이자. 이건 선택이 아니라 기본이다. 기본을 지키는 게 실력이다.

보안 취약점은 대부분 거창한 해킹 기술에서 오지 않는다. 이런 작은 설정 하나 빠뜨린 곳에서 온다. 내가 만드는 페이지의 모든 외부 링크를 지금 당장 점검해 보길 권한다. 아마 생각보다 많은 링크가 rel 속성 없이 있을 것이다. 발견할 때마다 고치는 게 아니라, 처음부터 올바른 습관으로 만드는 것이 개발자로서 성장하는 방식이다. 10년 넘게 코드를 만들어오면서 가장 오래 남는 교훈이 바로 그것이다. 기본을 지키는 것, 그리고 그 기본을 습관으로 만드는 것.


출처 및 참고 경로

  • OWASP 역방향 탭 나이팅(Reverse Tabnabbing) 취약점: https://owasp.org/www-community/attacks/Reverse_Tabnabbing
  • MDN rel 속성 문서: https://developer.mozilla.org/ko/docs/Web/HTML/Attributes/rel
  • Google SEO 외부 링크 가이드: https://developers.google.com/search/docs/crawling-indexing/qualify-outbound-links
  • HTML Living Standard rel 속성: https://html.spec.whatwg.org/multipage/links.html#linkTypes
  • WordPress 외부 링크 자동화 플러그인: https://wordpress.org/plugins/external-links/

소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 ⚡ 정보 부스터 🚀