<figure class="image image_resized" style="width:100%;"><a href="https://www.wishket.com/crsr/?next=/w/EaN4AhXVQN/&referer_type=7110000705"><img src="https://yozm.wishket.com/media/news/1586/%EC%9C%84%EC%8B%9C%EC%BC%93_%EC%A0%84%ED%99%98_%EB%B0%B0%EB%84%88.png"></a></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">여러분이 자주 방문하는 웹사이트에 접속하여 개발자 도구를 한 번 켜서 HTML 요소 검사기에서 하이퍼링크(<span style="color:#e52929;"><code><a></code></span>, 앵커 태그)들을 한 번 살펴보시기 바랍니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image002.png" alt="하이퍼링크 rel 속성값"><figcaption>왼쪽은 노션, 오른쪽은 디스커스(Disqus). 일부 웹 앱의 하이퍼링크에는 <code>rel</code> 속성의 값으로 <span style="color:#e52929;"><code>noopener</code></span>, <span style="color:#e52929;"><code>noreferrer</code></span>, <span style="color:#e52929;"><code>nofollow</code></span>가 걸려있는 걸 볼 수 있다.</figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">아마 전부는 아니지만, 일부 하이퍼링크에는 <span style="color:#e52929;"><code>rel</code></span>이라는 속성의 값으로 <span style="color:#e52929;"><code>noopener</code></span>, <span style="color:#e52929;"><code>noreferrer</code></span> 또는 <span style="color:#e52929;"><code>nofollow</code></span>가 들어있을 겁니다. 이러한 속성은 왜 들어있으며 어떤 역할을 하는 걸까요? 오늘은 그 이유에 대해 간단히 알아보고자 합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이번 포스트를 통해 <strong>하이퍼링크의</strong> <span style="color:#e52929;"><code>rel</code></span> <strong>속성으로 해당 값을 언제 어떻게 적용해야 하는지가 궁금하신 분</strong>들께 도움이 되기를 바랍니다.</p><div class="page-break" style="page-break-after:always;"><span style="display:none;"> </span></div><figure class="table"><table><tbody><tr><td><h4 style="text-align:justify;"><strong>TL;DR</strong></h4><ul><li style="text-align:justify;"><span style="color:#e52929;"><code>noopener</code></span>는 하이퍼링크에 <span style="color:#e52929;"><code>target="_blank"</code></span> 속성이 적용된 링크를 열 때 발생할 수 있는 <strong>탭 내빙(Tab nabbing) 공격</strong>을 방지하기 위해 사용된다.</li><li style="text-align:justify;"><span style="color:#e52929;"><code>noreferrer</code></span>는 <span style="color:#e52929;"><code>noopener</code></span>의 기본 동작에 더해, 해당 HTML 파일을 불러오기 위한 HTTP 요청을 보낼 때 <span style="color:#e52929;"><code>Referer</code></span> 헤더를 생략한다. 따라서 해당 사이트의 통계 수집에 영향을 줄 수 있다.</li><li style="text-align:justify;"><span style="color:#e52929;"><code>nofollow</code></span>는 하이퍼링크로 연결된 페이지를 신뢰할 수 없기 때문에 검색 엔진이 현재 웹사이트와 링크된 페이지를 연결하지 않기를 바라거나, 링크된 페이지를 크롤링하지 않기를 바라는 경우에 사용한다.</li><li style="text-align:justify;">위 속성들은 신뢰할 수 없는 불특정 다수가 웹사이트에 링크를 올릴 수 있는 기능이 제공될 때 적용하는 것이 적합하다.</li></ul></td></tr></tbody></table></figure><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>noopener</strong></h3><p style="text-align:justify;">여러분이 하이퍼링크를 클릭할 때, 해당 앵커 태그에 <span style="color:#e52929;"><code>target="_blank"</code></span> 속성이 적용되어 있었다면 두 가지 재미있는 일이 발생합니다. 바로 <strong>성능과 보안 면에서 취약점이 발생</strong>한다는 것입니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">우선 새롭게 열린 페이지는 원본 페이지와 동일한 프로세스에서 실행될 수 있습니다. 이는 새로 열린 페이지가 <strong>보조 브라우징 컨텍스트(auxiliary browsing context)</strong>이기 때문에, 자기 자신을 생성한 원본 브라우징 컨텍스트를 <strong>오프너 브라우징 컨텍스트(opener browsing context)</strong>라는 이름으로 참조하고 있기 때문입니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">따라서 새 페이지에서 많은 JavaScript를 실행하는 경우에는 <a href="https://jakearchibald.com/2016/performance-benefits-of-rel-noopener/">원본 페이지의 성능이 저하</a>될 수도 있습니다(아래에 설명할 내용이지만 최신 브라우저에서는 이러한 성능 문제가 기본적으로 발생하지 않게 처리가 된 상태입니다).</p><p style="text-align:justify;"> </p><p style="text-align:justify;">하지만 가장 큰 문제는 새롭게 열린 페이지에서 JavaScript를 통해 원본 페이지에 직접 접근이 가능해지는 것입니다. 이 원본 페이지는 <span style="color:#e52929;"><code>window.opener</code></span>를 이용해 접근이 가능한데, 이를 이용한 피싱 공격을 <strong>탭 내빙(Tab nabbing)</strong> 이라는 이름으로 부릅니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image004.png" alt="탭 내빙 순서도"><figcaption>탭 내빙의 순서도</figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;"><a href="https://blog.jxck.io/entries/2016-06-12/noopener.html">탭 내빙을 간단하게 설명해 둔 자료</a>가 있어 이를 가져왔습니다.</p><p style="text-align:justify;"> </p><blockquote><ol><li>우선 사용자가 <a href="http://cgm.example.com/">cgm.example.com</a>에 접속하고, 해당 사이트에서 <a href="http://happy.example.com/">happy.example.com</a>으로 갈 수 있는 외부 링크를 클릭합니다.</li><li>새 탭에서 <a href="http://happy.example.com/">happy.example.com</a>가 열립니다. 이때 <a href="http://happy.example.com/">happy.example.com</a>에서 <span style="color:#e52929;"><code>window.opener.location</code></span>을 피싱 사이트인 <a href="http://cgn.example.com/login">cgn.example.com/login</a>으로 변경합니다.</li><li>사용자가 본래의 탭으로 돌아오면, 로그인이 풀렸다고 생각하고 아이디와 비밀번호를 입력합니다.</li><li>피싱 사이트는 아이디와 비밀번호를 탈취한 후 다시 <a href="http://cgm.example.com/">cgm.example.com</a>으로 리다이렉션하므로 사용자는 눈치챌 수 없습니다.</li></ol></blockquote><p style="text-align:justify;"> </p><p style="text-align:justify;">이러한 탭 내빙 공격은 불특정다수가 외부 링크를 다른 사람에게 공유할 수 있는 메일이나 인터넷 커뮤니티 등에서 많이 발생했습니다. 여기에 대한 근본적인 원인은 바로 <span style="color:#e52929;"><code>window.opener</code></span>를 이용해 원본 페이지에 접근이 가능했기 때문이었죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/noopener">noopener</a> 속성값은 이를 막기 위해 등장했습니다. <span style="color:#e52929;"><code>noopener</code></span>를 적용하면 원본 페이지에 대한 컨텍스트 액세스를 제공하지 않고 새 탭에서 최상위 브라우징 컨텍스트를 새로 생성하여 링크를 열도록 브라우저에게 지시합니다. 따라서 새 페이지에서의 <span style="color:#e52929;"><code>window.opener</code></span>의 값은 <span style="color:#e52929;"><code>null</code></span>이 됩니다. 단순히 브라우징 컨텍스트의 연결을 끊어달라고 브라우저에게 말하는 것이기 때문에, 검색 엔진 최적화(SEO)에는 영향을 미치지 않습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">만약 이 글을 읽은 여러분께서 ‘나 여태껏 저렇게 코드 작성하지 않았는데 어떡하죠?’라고 걱정되실 수도 있습니다. 다행스럽게도 이러한 문제점은 웬만해서 발생하지 않을 것입니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">우선 이러한 탭 내빙 문제는 <span style="color:#e52929;"><code>target="_blank"</code></span> 일 때만 발생하고, 댓글처럼 하이퍼링크의 소스를 신뢰할 수 없는 사용자로부터 받아야 할 경우에만 적용하면 됩니다. 여러분이 직접 믿음직스러운(?) 사이트의 링크를 걸었다면 그것은 문제될 일이 없습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">또한 <a href="https://html.spec.whatwg.org/multipage/links.html#link-type-noopener">HTML 표준</a>의 변경에 맞추어, <a href="https://developer.chrome.com/blog/new-in-chrome-88/#more">크롬의 경우 88버전</a>, <a href="https://webkit.org/blog/8475/release-notes-for-safari-technology-preview-68/">사파리의 경우 68버전</a>부터 <span style="color:#e52929;"><code>target="_blank"</code></span>가 달린 하이퍼링크의 기본 동작이 <span style="color:#e52929;"><code>noopener</code></span>로 변경되었습니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image006.png" alt="HTML 표준 변경"><figcaption>HTML 스펙을 보면 <span style="color:#e52929;"><code>noopener</code></span>나 <span style="color:#e52929;"><code>noreferrer</code></span>가 없어도 기본적으로 <span style="color:#e52929;"><code>noopener</code></span>취급한다고 되어있다</figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">그런데 연도로 따지자면 사파리는 2018년, 크롬은 2021년에 기본 동작이 변경되었으므로 생각보다 최근에 적용된 것입니다. <span style="color:#e52929;"><code>noopener</code></span>가 기본 동작이 된 이상 앞으로 점차 사라지게 될 속성이지 않을까 생각해 봅니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">만약 굳이 새 탭에서 <span style="color:#e52929;"><code>window.opener</code></span>에 대한 접근이 필요하다면, <span style="color:#e52929;"><code>rel="opener"</code></span>를 설정하는 방식으로 해결 가능합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>noreferrer</strong></h3><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image008.png" alt="noreferrer 특정 헤더 생략"><figcaption>HTML 스펙을 보면 <span style="color:#e52929;"><code>noreferrer</code></span>의 경우에는 특정 헤더를 생략하라고 되어 있다</figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;"><span style="color:#e52929;"><code>noopener</code></span>의 기능과 동일하게, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/noreferrer"><span style="color:#e52929;"><code>noreferrer</code></span></a>는 새로 열린 사이트가 <span style="color:#e52929;"><code>window.opener</code></span> 객체에 접근하는 것을 방지하는 역할을 합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">하지만 여기서 <span style="color:#e52929;"><code>noreferrer</code></span>에는 더 나아가 추가 기능이 포함되어 있는데, 바로 <strong>브라우저가 해당 페이지를 불러오면서 HTTP 요청을 보낼 때</strong> <span style="color:#e52929;"><code><strong>referer</strong></code></span><strong>헤더를 생략하는 것</strong>입니다. 즉, <span style="color:#e52929;"><code>noreferrer</code></span> 설정값이 있으면 링크를 클릭할 때 해당 유입이 어디에서 발생하였는지에 대한 정보가 새 페이지에 제공되지 않습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">가령 누군가가 자신의 웹페이지에 여러분의 링크를 <span style="color:#e52929;"><code>noreferrer</code></span>를 사용해 하이퍼링크를 건 다음, 사용자가 해당 링크를 클릭하면 해당 사용자가 어디에서 왔는지를 알 수 없습니다. 따라서 구글 애널리틱스와 같은 통계 분석 도구에서 해당 트래픽은 <strong>추천 유입(Referral)</strong>이 아닌 <strong>직접 유입(Direct)</strong>으로 나타납니다. 따라서 해당 웹페이지의 통계 수치를 어느 정도 왜곡하게 되는(?) 특징이 있습니다. SEO에는 영향을 미치지 않습니다. 물론 마케팅 담당하시는 분께는 이런 것들이 캠페인 목표 설정하는 데 있어 조금 문제가 될 수도…</p><p style="text-align:justify;"> </p><p style="text-align:justify;">그렇다면 언제 <span style="color:#e52929;"><code>noreferrer</code></span>를 사용해야 하고 언제 <span style="color:#e52929;"><code>noopener</code></span>를 사용해야 할까요? <strong>일반적으로는 둘 다 사용하는 것이 좋습니다.</strong> 이는 브라우저 호환성 때문이고, 문제를 일으키는 녀석은 역시 IE입니다. 대부분의 최신 브라우저는 두 속성 모두를 지원하지만 일부 구형 브라우저의 경우에는 <span style="color:#e52929;"><code>noreferrer</code></span>만 지원하는 경우가 있기 때문입니다. 따라서 일반적으로는 두 속성값을 모두 적어주어야 합니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image010.png" alt="개발자 도구 네트워크 탭"><figcaption>위는 <span style="color:#e52929;"><code>noopener</code></span>, 아래는 <span style="color:#e52929;"><code>noreferrer</code></span>. 실제로 개발자 도구의 네트워크 탭에서 HTTP 헤더 차이를 볼 수 있다.</figcaption></figure><p style="text-align:justify;"> </p><blockquote><p style="text-align:justify;">개발자 도구에서 볼 때는 HTTP 헤더 이름이 <span style="color:#e52929;"><code>r</code></span>이 하나 빠진 <span style="color:#e52929;"><code>referer</code></span>라고 되어 있는데 이건 놀랍게도(?) <a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Referer">HTTP 사양을 정의할 때 오타난 것</a>이 그대로 표준이 된 경우(…)라고 합니다.</p></blockquote><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>nofollow</strong></h3><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/1586/image012.png" alt="nofollow 댓글 링크"><figcaption><span style="color:#e52929;"><code>nofollow</code></span>는 일반적으로 댓글에 달리는 링크에 주로 사용한다</figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;"><a href="https://ko.wikipedia.org/wiki/Nofollow"><span style="color:#e52929;"><code>nofollow</code></span></a> 속성값은 <strong>검색 엔진에게 링크된 웹사이트를 보증하거나 신뢰할 수 없으니 현재 웹사이트와 연결하지 않기를 바라는 경우</strong>에 사용합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">사실 <span style="color:#e52929;"><code>nofollow</code></span> 속성값이 등장한 이유가 바로 <strong>스팸 댓글</strong> 때문입니다. 구글은 웹사이트 간 링크 연결 그래프, 페이지의 평판과 신뢰도를 바탕으로 검색 결과를 순위화하는 알고리즘인 <a href="https://en.wikipedia.org/wiki/PageRank">PageRank</a>를 개발했는데, 각 블로그에 무분별하게 달린 스팸 댓글이 페이지 순위에 영향을 주었습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">스팸 댓글이 달린 게시글은 사이트 소유자의 의도와는 상관없이 평판이 내려가게 되었는데요, 구글은 이에 대한 해결책으로 <span style="color:#e52929;"><code>nofollow</code></span> 옵션이 제공된 링크는 크롤링하지 않고 검색 엔진에도 영향을 미치지 않게 로직을 바꾸기로 했습니다. 따라서 일반적으로 <span style="color:#e52929;"><code>nofollow</code></span> 속성값은 댓글이나 포럼처럼 사용자가 참여 콘텐츠의 링크에 적합합니다. 위의 두 속성에 비교하자면 실제로 웹사이트 SEO에 영향을 미칠 수도 있습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">사실 구글에서는 이처럼 사이트 소유자가 완전히 신뢰할 수는 없지만, PageRank의 순위에는 영향을 미칠 수 있는 <a href="https://developers.google.com/search/docs/advanced/guidelines/qualify-outbound-links?hl=ko">링크의 종류를 추가로 구분</a>해두었습니다. 왜냐하면 <span style="color:#e52929;"><code>nofollow</code></span> 속성값을 이용해 돈이 되는 링크들만 검색 엔진에 전달하는 어뷰징 사례가 있었거든요.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">그래서 돈을 받고 광고를 걸어주는 링크 같은 경우는 <span style="color:#e52929;"><code>sponsored</code></span>, 댓글 및 포럼과 같은 사용자 참여 콘텐츠는 <span style="color:#e52929;"><code>ugc</code></span> 등으로 구분합니다. 하지만 개인적 경험상으로 이 정도 수준까지 엄격하게 속성을 구분해둔 적은 없었던 것 같아서, ‘일단은 이런 게 있다’ 정도만 알아두면 좋을 것 같습니다. (위의 예시 이미지에서는 <span style="color:#e52929;"><code>ugc</code></span>를 함께 명시해준 모습을 볼 수 있습니다.)</p><p style="text-align:justify;"> </p><p style="text-align:justify;">하지만 <span style="color:#e52929;"><code>nofollow</code></span> 속성값이 적용되었다고 해서 해당 페이지의 크롤링을 완전히 막을 수는 없습니다. 해당 페이지가 다른 웹사이트의 링크로부터 연결될 수가 있기 때문이죠. 따라서 본인 소유의 페이지 크롤링을 막기 위해선 <span style="color:#e52929;"><code>nofollow</code></span> 속성값을 쓰기보다는 <span style="color:#e52929;"><code>robots.txt</code></span> 또는 메타 태그를 이용하는 것이 가장 좋은 방법입니다.</p>