⚽️ 목표
다른 페이지를 새창에 띄울 시 "noopener를 꼭해줘야 해요! 보안적 허점이 생긴다구요오오옷~!" 라고 뭉뚱그리지 말고 왜 취약한지 araboza
TL;DR
최신 브라우저에서는 noopener attribute가 없어도 새로열린 자식창에서 부모창 참조는 불가능하다.
•
최신 브라우저에는 noopener를 명시적으로 적어주지 않아도 target="\_blank"시 기본적으로 적용되어있다.
•
“그렇다고... 당신이 만든 웹의 이용자가 모두 최신 브라우저를 사용한다는 착각에 빠.져.있.진.안.켔.찌???!?!”
생명체의 절반이 사라져야 합니다
1. 들어가기 전에
새로운 페이지를 새 창에서 열 시 noopener attribute가 없으면 자식창에서 window.opener 객체를 이용해 부모창을 제어할 수 있다.
•
noopener를 사용해야하는 이유는 그러하다. → 적어도 우리가 알고있기에는.
•
다들 “취약하니까 넣어야한다.”를 이야기하고 있으니 우리는 모두 해당 attribute를 넣어야한다는 사실을 알고 있다.
•
이 글은 “어떤 취약점인가?”, “왜 취약한가?”, “아직도 취약한가?”, “최신 브라우저는 업데이트 안하고 뭐하나?”와 같은 후속질문에 대답하기 위한 글이다.
•
물론 “취약점이니까 a태그에서 새로운 창을 열때는 무조건 noopener attribute를 넣어야한다.”에서 그냥 무조건 넣기만해도 일반적인 업무나 협업 관점에서는 충분하지만 본인의 생각은 조금 다르다.
◦
내가 어떠한 액션을 취할때는 그에 합당한 이유와 최소한의 히스토리를 알아야 문제가 생겼을때 대응이 가능하기 때문이다. 이 두개가 충족되지 않을 경우 문제가 생겼을 때 해당 문제는 예기치 못한 문제가 발생하는 경우가 많았다.
2. 1 회차 시도
•
왜 1차 시도인지는 읽다보면…
유도하는 상황
graph TD A(A - 취약한 링크를 가지고 있는 페이지) ---> B(B - A로인해 열린 페이지) B-. 부모페이지 참조 시도 .-> A
Mermaid
복사
1.
A페이지에 취약한 링크를 삽입하여 이용자가 클릭하도록 유도한다.
2.
A로부터 열린 B 페이지에서 window.opener를 참조 시도한다.
•
결과적으로 2번 단계에서는 B가 window.opener.location를 이용하여 부모 페이지인 A의 현재 주소를 변조하여 피싱사이트로 이용자를 이동시키는게 목적이다.
opener를 알아보자
<!-- noopener없이 B를 새창에서 여는 취약한 링크를 가지고 있는 A 페이지 -->
<a link="https://www.B.com" target="_blank">취약한 링크! </a>
HTML
복사
•
A 페이지에서 해당 링크 클릭 시 새창에 B 페이지가 열린다.
// www.B.com
// A로 부터 새창에 열린 B 페이지
// 새로운 창에 B 페이지의 브라우저 개발자 도구 콘솔에서 실행 시
window.opener; // null
JavaScript
복사
•
부모 창의 global 객체가 참조되지않.는.다.
•
나를 open한 부모 창의(A 페이지) global 객체가 나와야 하는데.. 왜 null이 나오는거지?
•
수많은 블로그 글들이 잘못된것인가? 아님 내가 모자란것인가?
◦
진지하게 이 생각 15초 정도 함…
2-1. Today’s 통수
safari는 2019년 부터, chrome은 2021년 초반 부터 추가된 기능으로 a 태그에 rel=noopener를 명시적으로 적어주지 않아도 noopener attribute가 자동으로 적용된다.
•
오히려 a 태그에 rel=opener를 명시적으로 입력해줘야 window.opener로 부모 브라우저의 global 객체에 접근할 수 있다.
•
아무값이 안들어가면 noopener가 attribute가 자동으로 적용된다.
패치버전
•
크롬 88.0.4324.96 버전 → 2021년 1월 19일에 업데이트 됐으며 새 창을 여는 링크의 경우 자동으로 noopener attribute가 적용된다.
•
사파리 11.1 → 2018년 3월에 noopener 사용 가능한 기능이 업데이트 됐으며 14.1버전에서 부터는 새 창을 여는경우 자동으로 noopener attribute가 적용된다.
3. 2 회차 시도
rel=”opener”로 바꿔보자
<!-- noopener없이 B를 새창에서 여는 취약한 링크를 가지고 있는 A 페이지 -->
<a link="https://www.B.com" target="_blank" rel="opener">
취약한 링크!
</a>
HTML
복사
•
해당 링크 클릭 시 새로운창에 B 페이지가 뜬다.
// 새로운 창에 뜬 네이버에서 브라우저 개발자도구 콘솔에서 실행 시
window.opener; // global {window: global, self: global, location: {…}, closed: false, frames: global, …}
JavaScript
복사
•
현재 창을 열은 부모 창을 참조할 수 있는 전역 객체
•
드디어 부모 창의 전역 객체에 접근 가능 -> 부! 모! 창을 조작 할 수있다고!?!?!?!?!?
•
아직까진 이해가 잘되지않을 것 이다. 부모창 조작 가능의 힘을. 느껴라.
4. Reverse tabnabbing
A(부모) -> B(자식) 새로운 창에 열린 자식 창이 부모창을 다른 주소로 리다이렉트 시키는 공격 기법
•
부모 브라우저의 window 객체에 접근 가능하다 === 브라우저의 전역 객체를 건들 수 있다는 뜻
•
해당 취약점이 제일 많이 사용되는 케이스는 Reverse Tabnabbing -> 부모 사이트를 피싱 사이트로 재이동 시키기
이동 시키기가 그렇게 취약점이야?
•
디자인이 똑같은 피싱 사이트로 이동 시키면 이용자는 당연하게 생각하고 계정정보 입력 후 로그인을 시도한다.
•
하지만 계정 정보는 피싱 사이트를 만든 공격자의 서버로 이동되므로 이용자의 계정정보가 공격자에게 탈취된다.
공격 예시
graph LR A(A - 취약한 웹사이트) B(B - A에 링크로 존재하는 Reverse tabnabbing을 수행하는 공격 사이트) C(C - A를 따라 만든 피싱 사이트)
Mermaid
복사
sequenceDiagram participant A participant B A->>B: 1. A에서 링크를 눌러 Reverse tanabbing 수행하는 페이지로 이동 B->>A: 2. B 페이지는 부모 윈도우(A)의 객체를 참조해 피싱 사이트인 C로 이동 A->>C: 3. A가 피싱 페이지인 C로 이동됨 Note over C: 4. A와 똑같이 생긴 C 페이지에서 <br/> 개인정보 입력 시<br/> 공격자는 피해자 개인정보 탈취
Mermaid
복사
1.
피해자가 A에서 서비스 이용 중
2.
A에 존재하는 링크를 타고 C 사이트로 이동
3.
C가 Reverse tabnabbing을 수행하여 A 부모 페이지에 존재하던 A를 B로 리다이렉트한다.
•
A를 리다이렉트 하는 C 코드
<html>
<body>
<script>
if (window.opener) {
window.opener.location = "C 주소";
}
</script>
</body>
</html>
HTML
복사
4.
피해자는 B에서 로그인 정보 입력하여 로그인 시도
5.
공격자가 피해자 로그인 정보 획득
•
이용자의 계정 정보는 성공적으로 공격자에게 탈취됐다.
5. noreferrer
noopener와 쌍둥이로 같이 자주쓰이는 링크의 rel(ationship)attribute
•
http 헤더에 referer 속성을 없애주는 attribute
http Referer 헤더
•
해당 페이지를 방문하는 이용자가 어느 페이지에서 방문한건지 추적할 수 있게 해주는 헤더
•
a 태그에 noreferrer를 사용 시 Referer 헤더가 사라져 해당 사이트에서 이전 사이트 추적이 불가능해짐
사용이유
noopener를 지원하지 않는 브라우저에서는 noreferrer로 작성 시 noopener가 해결하는 문제를 대신해서 해결해준다.
•
항상 둘이 붙어서 한세트로 소환되는 이유를 한마디로 말하자면 noopener보다 더 나은 호환성이다.
◦
대표적인 예로 IE11에서는 noopener 속성이 존재하지 않는다. → 하지만 noreferrer가 있을 경우 noopener처럼 작동한다.
◦
이외 (구버전) 브라우저들도 noopener보다 noreferrer를 더 많이 지원한다.
6. 결론
브라우저 사용자 → 브라우저 최신 버전을 쓰자
개발자 → 모든 이용자가 최신 브라우저를 사용한다는 망각에서 빠져나와서 개발하자
•
최신 버전의 브라우저에선 억지로 터지게 만들지 않는 이상 터지지 않는 취약점이다.
•
새 창을 여는 링크에 해당 attribute가 빠질 경우 Reverse Tabnabbing 취약점을 이용해 이용자를 피싱 사이트로 유도 할 수 있다.
•
noreferrer는 noopener 보다 더 호환성이 좋다. 하위호환을 위해 이왕 쓰는거 같이 써주자.
서비스 이용자들은 어떻게 해야할까
•
브라우저 버전 최신으로 업데이트 하고 편하게 사용하면 OK
◦
는 너무 수동적인 자세, 취약점은 어디든 존재한다. 항상.
•
조금만 낌세가 이상하더라도 “이 URL이 맞는 URL가?”라는 질문을 항상하자.
개발자들은 어떻게 해야할까
•
모든 이용자가 최신 브라우저를 사용하는게 아니니 a태그에서 새로운 창으로 열때는 rel=noopener noreferrer를 꼭 추가하자.