Popups and window methods, Cross-window communication, The clickjacking attack
Popups and window methods
팝업 창(popup window)
1
window.open("https://javascript.info/");
- 사용자에게 추가 문서를 표시하는 가장 오래된 방법 중 하나. 주어진 URL 이 포함된 새 창이 열림
- 대부분의 최신 브라우저는 별도의 창 대신 새 탭에서 URL을 열도록 구성됨
- 초기 아이디어는 메인 창을 닫지 않고 다른 컨텐츠를 표시하는 것이었지만 현재는 이를 수행하는 다른 방법을 사용
fetch
로 컨텐츠를 동적으로 로드하고 동적으로 생성된<div>
에 표시
- 여러 창을 동시에 표시하지 않는 모바일 장치에서는 팝업이 까다로움
팝업이 여전히 사용되는 작업
- 위의 단점에도 불구하고 다음과 같은 이유로 팝업이 여전히 사용되는 작업이 있음
- OAuth 승인(Google/Facebook/…으로 로그인) 등
- 팝업은 자체적으로 독립적인 자바스크립트 환경을 갖는 별도의 창이고 팝업을 여는 것은 매우 쉬움
- 신뢰할 수 없는 제3자 사이트에서 팝업을 여는 것은 안전
- 팝업은 탐색(URL 변경)하고 오프너(opener) 창으로 메시지 전송 가능
Popup blocking
- 과거에는 악성 사이트에서 팝업을 많이 악용했음
- 이제 대부분의 브라우저는 팝업을 차단하고 사용자를 보호
- 대부분의 브라우저는
onclick
같은 사용자 트리거 이벤트 핸들러 외부에서 호출되는 경우 팝업을 차단
1
2
3
4
window.open("https://javascript.info"); // 팝업 차단
button.onclick = () => window.open("https://javascript.info"); // 팝업 허용
setTimeout(() => window.open("http://google.com"), 1000); // 1초 후 팝업 열림
setTimeout(() => window.open("http://google.com"), 3000); // Firefox에서는 열리지 않음
- 원치 않는 팝업으로부터 어느 정도 사용자가 보호되지만 완전히 막을 수는 없음
- Firefox에서는 2000ms 이후에는 신뢰를 제거해 팝업이 열리지 않음
window.open
1
window.open(url, name, params);
url
: 새 창에 로드할 URLname
: 새 창의 이름. 해당 이름의 창이 있는 경우 해당 URL이 해당 창에서 열리고, 그렇지 않다면 새 창이 열림- 각 창에는
window.name
이 있어 팝업에 사용할 창 지정 가능
- 각 창에는
params
: 새 창의 구성 문자열. 쉼표로 구분된 설정을 포함하고 공백이 없어야 함
params
에 대한 설정
left/top
(숫자): 화면의 창 왼쪽 상단 모서리 좌표- 새 창은 화면 밖에 위치할 수 없음
width/height
(숫자): 새 창의 너비·높이- 최소 제한이 있어 보이지 않는 창을 만들 수 없음
menubar
(yes/no): 새 창에 브라우저 메뉴를 표시/숨김toolbar
(yes/no): 새 창에서 브라우저 탐색 표시줄을 표시/숨김location
(yes/no): 새 창에 URL 필드를 표시/숨김status
(yes/no): 상태 표시줄을 표시/숨김(대부분의 브라우저는 강제로 표시)resizable
(yes/no): 새 창의 크기 조정을 비활성화(권장되지 않음)scrollbars
(yes/no): 새 창의 스크롤 막대 비활성화(권장되지 않음)
Example: a minimalistic window
1
2
3
let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=0,height=0,left=-1000,top=-1000`;
open("/", "test", params); // 크롬에서 새 탭으로 열림..
1
2
3
let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=600,height=300,left=100,top=100`;
open("/", "test", params);
생략된 설정에 대한 규칙
open
호출에 3번째 인수가 없거나 비었으면 기본 창 매개변수가 사용됨- 매개변수 문자열이 있으나
yes/no
가 생략된 경우no
로 간주 left/top
이 없으면 브라우저는 마지막으로 열린 창 근처에서 새 창을 열음width/height
가 없으면 새 창은 마지막으로 열었던 것과 동일한 크기가 됨
Accessing popup from window
open
: 호출하면 새 창에 대한 참조를 반환- 프로퍼티를 조작하고 위치를 변경하는 등의 작업에 사용
1
2
let newWin = window.open("about:blank", "hello", "width=200,height=200");
newWin.document.write("Hello, world!"); // 자바스크립트로 팝업 컨텐츠 생성
1
2
3
4
5
6
7
let newWindow = open("/", "example", "width=300,height=300");
newWindow.focus();
alert(newWindow.location.href); // (*) about:blank, loading hasn't started yet
newWindow.onload = function () {
let html = `<div style="font-size:30px">Welcome!</div>`;
newWindow.document.body.insertAdjacentHTML("afterbegin", html);
};
window.open
직후에는 새 창이 아직 로드되지 않음 ((*)
에서 확인 가능)onload
가 그것을 수정하기를 기다림DOMContentLoaded
핸들러를newWinow.document
에 사용할 수도 있음
Same origin policy
- 창들은 동일한 출처(same origin)에서 온 경우에만 서로의 컨텐츠에 자유롭게 접근(access)
- Same origin: same
protocol://domain:port
- 메인 창이
site.com
에 있고 팝업이gmail.com
에 있는 경우, 사용자 안전상의 이유로 불가
Accessing window from popup
window.opener
참조를 사용해opener
창에 접근 할 수 있음- 팝업을 제외한 모든 창에서
null
- 창 사이의 연결은 양방향. 메인 창과 팝업은 서로 참조
1
2
3
4
let newWin = window.open("about:blank", "hello", "width=200,height=200");
newWin.document.write(
"<script>window.opener.document.body.innerHTML = 'Test'</script>"
); // opener(현재) 창의 내용이 "Test"로 대체됨
Closing a popup
win.close()
: 창 닫기. 기술적으로는 모든window
에서 사용 가능한 메서드window
가window.open()
으로 생성되지 않았다면 대부분의 브라우저에서window.close()
는 무시됨- 따라서 팝업에서만 작동
win.closed
: 창이 닫혔는지 확인. 닫혔으면true
- 팝업이나 메인 창이 열려있는지 아닌지 확인하는 데 유용
- 사용자는 언제든지 닫을 수 있기 때문에 이런 가능성을 고려해야 함
1
2
3
4
5
let newWindow = open("/", "example", "width=300,height=300");
newWindow.onload = function () {
newWindow.close(); // 창을 로드한 후 닫음
alert(newWindow.closed); // true
};
Scrolling and resizing
win.moveBy(x, y)
: 현재 위치를 기준으로 창을 오른쪽으로x
px, 아래 쪽으로y
px 이동. 음수 허용win.moveTo(x, y)
: 창을(x, y)
좌표로 이동win.resizeBy(width, height)
: 현재 크기를 기준으로width/height
만큼 창 크기 조정. 음수 허용win.resizeTo(width, height)
: 창을 주어진 크기로 조정window.onresize
이벤트- 추가 탭이 없는 팝업에서만 안정적으로 작동
- 남용을 방지하기 위해 브라우저는 일반적으로 이러한 방법을 차단
- 이동/크기 조정 방법은 최대화/최소화된 창에서는 작동하지 않음
- 자바스크립트에는 창을 축소하거나 최대화할 수 있는 방법이 없음
- 이러한 OS 수준 기능은 FE 개발자에게 숨겨짐
Scrolling a window
win.scrollBy(x, y)
win.scrollTo(x, y)
elem.scrollIntoView(top=true)
window.onscroll
Focus/blur on a window
window.focus()
,window.blur()
- 이론적으로 두 메서드를 사용해 창에 포커스하고 해제하는 것이 가능
focus/blur
이벤트: 방문자가 창에 집중하고 다른 곳으로 전환하는 순간을 포착- 실제로는 과거에 사악한 페이지가 이를 남용했기 때문에 사용이 제한됨
- 모바일 브라우저는 일반적으로
window.focus()
를 완전히 무시 - 새 창이 아닌 별도의 탭에서 팝업이 열리는 경우에도 포커스 작동하지 않음
- 모바일 브라우저는 일반적으로
- 유용할 수 있는 사례
- 팝업을 열 때
newWindow.focus()
를 실행하는 것이 좋음- 일부 OS/브라우저 조합의 경우 사용자가 새 창에 있는지 확인
- 방문자가 실제로 웹앱을 사용하는 시점을
window.onfocus/onblur
를 이용해 추적할 수 있음- 페이지 내 활동, 애니메이션 등을 일시중지하거나 재개할 수 있음
- 팝업을 열 때
1
window.onblur = () => window.focus(); // 사용자가 창 밖으로 전환하려 하면 창에 다시 포커스
Cross-window communication
Same Origin Policy(동일 출처 정책)
- 창과 프레임 간의 접근을 제한하고 정보 도용으로부터 사용자를 보호
- 사용자가 두 개의 페이지(
john-smith.com
,gmail.com
)를 열어 둔 경우 john-smith.com
의 스크립트가gmail.com
의 메일을 읽는 것을 원하지 않을 것
Same Origin
- 두 URL이 동일한 프로토콜, 도메인, 포트를 갖는 경우 동일한 출처(same origin)를 갖는다고 함
- 다음 URL은 모두 동일한 출처를 공유
http://site.com
http://site.com/
http://site.com/my/page.html
- 다음은 그렇지 않음
http://www.site.com
: 다른 도메인(www.
)http://site.org
: 다른 도메인(.org
)https://site.com
: 다른 프로토콜(https
)http://site.com:8080
: 다른 포트(8080
)
동일 출처 정책은 다음과 같이 명시함
- 다른 창에 대한 참조가 있고, 해당 창이 동일한 출처에서 온 경우 해당 창에 대한 전체 접근 권한이 있음
- 다른 창:
window.open
으로 생성된 팝업,<iframe>
내부의 창
- 다른 창:
- 그렇지 않고 다른 출처에서 온 경우 해당 창의 내용(변수, 문서 등)에 접근 불가
- 유일한 예외는
location
(변경해서 사용자를 리디렉션함) - 그러나
location
을 읽을 수 없고 사용자가 현재 어디에 있는지 알 수 없어 정보가 유출되지 않음
In action: iframe
- 별도의
document
,window
객체를 포함하는 별도의 내장 창을 호스팅 iframe.contentWindow
:<iframe>
내부의 창 가져오기iframe.contentDocument
:<iframe>
내부의 문서 가져오기 (iframe.contentWindow.document
)- 포함된 창 내부에 접근하면 브라우저는 iframe 출처가 동일한지 확인. 동일하지 않으면 접근 거부
location
에 쓰는 것은 예외이지만 여전히 허용됨iframe.onload
와iframe.contentWindow.onload
iframe.onload
이벤트(<iframe>
태그의)는iframe.contentWindow.onload
(임베드된 window 객체)와 기본적으로 동일- 임베드된 창이 모든 리소스와 함께 완전히 로드되면 트리거됨
- 그러나 다른 출처의 iframe에서
iframe.contentWindow.onload
에 접근할 수 없으므로iframe.onload
를 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 다른 원본에서 읽고 쓰기 시도 -->
<iframe src="https://example.com" id="iframe"></iframe>
<script>
iframe.onload = function () {
let iframeWindow = iframe.contentWindow; // OK (내부 창에 대한 참조를 얻을 수 있음)
try {
let doc = iframe.contentDocument; // ERROR (내부의 문서는 불가)
} catch (e) {
alert(e); // Security Error (다른 출처)
}
try {
let href = iframe.contentWindow.location.href; // ERROR (Location 객체에서 URL을 읽을 수 없음)
} catch (e) {
alert(e); // Security Error (iframe의 페이지 URL을 읽을 수 없음)
}
iframe.contentWindow.location = "/"; // OK (location에 쓸 수 있고 iframe에 뭔가를 로드할 수 있음)
iframe.onload = null; // clear the handler, not to run it after the location change
};
</script>
- 내부 창에 대한 참조를 얻는
iframe.contentWindow
에 대한 작업,location
에 쓰기를 제외한 모든 작업에 대해 에러 표시
1
2
3
4
5
6
7
<!-- iframe from the same site -->
<iframe src="/" id="iframe"></iframe>
<script>
iframe.onload = function () {
iframe.contentDocument.body.prepend("Hello, world!"); // 무엇이든 작업 가능
};
</script>
- iframe이 동일한 출처를 가지고 있다면 그것을 가지고 무엇이든 할 수 있음
Windows on subdomains: document.domain
- 정의에 따르면 도메인이 다른 두 URL의 출처는 다르지만, 창이 동일한 두 번째 수준 도메인을 공유하는 경우
john.site.com
,peter.site.com
,site.com
이들의 공통 두 번째 수준 도메인은site.com
- 창 간 통신을 목적으로 브라우저가 해당 차이점을 무시해 ‘동일한 출처’에서 온 것으로 처리될 수 있음
- 작동하게 하려면 각 창에서
document.domain = "site.com";
코드를 실행해 제한 없이 상호작용 가능 - 다시 말하지만, 이는 동일한 두 번째 수준 도메인이 있는 페이지에만 가능
- 하지만 최근 보안상의 문제로
document.domain
에 값을 설정하는 것이 금지됨
Iframe: wrong document pitfall
- iframe이 동일한 출처에서 왔으며 그것의
document
에 접근할 수 있는 경우, 함정이 있음- 교차 출처와 관련은 없지만 아는 것이 중요
- iframe이 생성되면 즉시 문서(document)가 생성되지만, 해당 문서는 로드되는 문서와 다름
- 따라서 문서에 대해 즉시 작업을 수행하면 해당 내용이 손실될 수 있음
- 아직 로드되지 않은 iframe의 문서로 작업하면 안 됨
- 그 문서는 잘못된 문서이기 때문. 이벤트 핸들러를 설정하면 무시됨
- 문서가 있는 순간을 감지하는 방법
- 올바른 문서는
iframe.onload
가 트리거 되면 확실히 제자리에 있음 - 그러나 모든 리소스가 포함된 전체 iframe이 로드될 때만 트리거됨
setInterval
로 검사해 그 순간을 더 빨리 포착할 수 있음
- 올바른 문서는
1
2
3
4
5
6
7
8
<iframe src="/" id="iframe"></iframe>
<script>
let oldDoc = iframe.contentDocument;
iframe.onload = function () {
let newDoc = iframe.contentDocument;
alert(oldDoc == newDoc); // false (로드된 문서는 처음과 같지 않음)
};
</script>
1
2
3
4
5
6
7
8
9
10
<iframe src="/" id="iframe"></iframe>
<script>
let oldDoc = iframe.contentDocument;
let timer = setInterval(() => {
let newDoc = iframe.contentDocument;
if (newDoc == oldDoc) return;
alert("New document is here!");
clearInterval(timer); // 더이상 필요하지 않으므로 취소함
}, 100); // 문서가 새것인지 100ms마다 체크
</script>
Collection: window.frames
<iframe>
의 window 객체를 가져오는 다른 방법window.frames
기명 컬렉션에서 가져오기window.frames[0]
: document의 첫번쩨 프레임에 대한 window 객체window.frames.iframeName
:name="iframeName"
- iframe 내부에는 다른 iframe이 있을 수 있음
- 해당
window
객체는 계층 구조를 형성
- 해당
- 탐색 링크
window.frames
: children 창의 컬렉션 (중첩된 프레임용)window.parent
: parent(외부) 창에 대한 참조window.top
: 최상위 창에 대한 참조. 현재 문서가 프레임 내부에 열려 있는지 확인 가능
1
2
3
4
5
<iframe src="/" style="height:80px" name="win" id="iframe"></iframe>
<script>
alert(iframe.contentWindow == frames[0]); // true
alert(iframe.contentWindow == frames.win); // true
</script>
1
window.frames[0].parent === window; // true
1
2
3
4
5
if (window == top) {
alert("The script is in the topmost window, not in a frame");
} else {
alert("The script runs in a frame!");
}
The “sandbox” iframe attribute
sandbox
속성: 신뢰할 수 없는 코드가 실행되는 것을 방지하기 위해<iframe>
내부에서 특정 작업(action)을 제외할 수 있음- iframe을 다른 출처에서 온 것으로 처리하거나 다른 제한사항을 적용해 iframe을 ‘샌드박스’함
<iframe sandbox src="...">
에 적용되는 기본 제한 세트가 있음- 하지만 속성 값으로 적용하면 안 되는 제한사항을 공백으로 구분하여 제공하면 완회될 수 있음
- 예:
<iframe sandbox="allow-forms allow-popups">
- 예:
- 즉 빈
sandbox
속성은 가능한 한 가장 엄격한 제한을 두지만, 해제하려는 속성은 공백으로 구분된 목록을 넣을 수 있음
제한 사항 목록
allow-same-origin
- 기본적으로
sandbox
는 iframe에 대해 다른 출처 정책을 강제 적용함 - 즉
src
가 동일한 다른 사이트를 가리키더라도 브라우저가 iframe을 다른 출처에서 온 것으로 처리하도록 만듦 - 스크립트에 대한 모든 암시적 제한사항 포함
- 이 옵션은 해당 기능을 제거
- 기본적으로
allow-top-navigation
: iframe이parent.location
을 변경할 수 있도록 허용allow-forms
: iframe에서 폼을 제출할 수 있음allow-scripts
: iframe에서 스크립트를 실행할 수 있음allow-popups
: iframe에서window.open
팝업을 허용sandbox
속성의 목적은 단지 더 많은 제한사항을 추가하는 것- 제거할 수 없음. 특히 iframe이 다른 출처에서 온 경우 동일 출처 제한을 완화할 수 없음
Cross-window messaging
1
postMessage(data, targetOrigin);
postMessage
인터페이스- window의 출처에 관계 없이 서로 대화 가능. 동일 출처 정책을 우회하는 방법
john-smith.com
에서gmail.com
에 대화하고 정보 교환 가능
- 둘 다 동의하고 해당 자바스크립트 함수를 호출하는 경우에만 가능. 그래야 사용자가 안전해짐
- 메시지를 보내려는 window는 수신하는 window의
postMessage
를 호출- 즉, 메시지를
win
에 보내려면win.postMessage(data, targetOrigin)
을 호출해야 함
- 즉, 메시지를
- 인터페이스는 두 부분으로 구성
data
: 전송할 데이터. 모든 객체가 될 수 있고 데이터는 structured cloning algorithm을 사용하여 복제됨targetOrigin
: 지정된 오리진의 window만 메시지를 받게 대상 window의 오리진을 지정. 데이터가 민감한 경우 중요- 지정하면 window는 여전히 올바른 사이트에 있는 경우에만 데이터를 수신.
*
로 설정하면 확인하지 않음
- 지정하면 window는 여전히 올바른 사이트에 있는 경우에만 데이터를 수신.
onmessage
- 메시지를 받으려면 대상 window의
message
이벤트에 핸들러가 있어야 함 postMessage
가 호출되면 트리거 (targetOrigin
확인도 성공적인 경우)- 이벤트 객체의 특별한 프로퍼티
data
:postMessage
로부터의 데이터origin
: 발신자의 오리진source
: 보낸 window에 대한 참조.source.postMessage(...)
로 돌아갈 수 있음addEventListener
를 사용해 핸들러를 할당해야 함.window.onmessage
는 동작하지 않음
1
2
3
4
5
6
<iframe src="http://example.com" name="example"></iframe>
<script>
let win = window.frames.example;
win.postMessage("message", "http://example.com"); // win은 오리진 http://example.com의 문서가 있는 경우에만 메시지를 수신
// win.postMessage("message", "*");
</script>
1
2
3
4
5
window.addEventListener("message", function (event) {
if (event.origin != "http://javascript.info") return; // 모르는 도메인은 무시
alert("received: " + event.data);
// can message back using event.source.postMessage(...)
});
The clickjacking attack
클릭재킹 공격
- 악의적인 페이지가 방문자를 대신해 피해자 사이트를 클릭할 수 있음
The idea
Facebook에서 클릭재킹이 수행된 방법
- 방문자가 사악한 페이지로 유도됨 (방법은 중요하지 않음)
- 페이지에 무해해 보이는 링크가 있음
- 지금 부자가 되세요, 여기를 클릭하세요 매우 재밌습니다
- 해당 링크 위에는 사악한 페이지가
src
가 facebook.com인 투명한 iframe을 배치해 좋아요 버튼이 해당 링크 바로 위에 위치하게 함- 일반적으로
z-index
로 수행됨
- 일반적으로
- 방문자는 링크를 클릭하려고 하면서 실제로 버튼을 클릭하게 됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
iframe {
/* iframe from the victim site */
width: 400px;
height: 100px;
position: absolute;
top: 0;
left: -20px;
opacity: 0.5; /* 실제로는 opacity:0 */
z-index: 1;
}
</style>
<div>Click to get rich now:</div>
<!-- The url from the victim site -->
<iframe src="/clickjacking/facebook.html"></iframe>
<button>Click here!</button>
<div>...And you're cool (I'm a cool hacker actually)!</div>
- 버튼을 클릭하면 실제로 iframe이 클릭되지만 투명(현재는 반투명)하기 때문에 사용자에게는 표시되지 않음
- 결과적으로 방문자가 Facebook에서 승인을 받은 경우(대개 기억하기(remember me)가 켜져 있음) 좋아요가 추가됨
- 트위터에서는 팔로우 버튼이 될 것
클릭재킹은 키보드가 아닌 클릭을 위한 것
- 공격은 마우스 동작(또는 모바일의 탭과 같은 유사한 동작)에만 영향을 미침
- 키보드 입력은 리디렉션하기 훨씬 어려움
- 기술적으로 해킹할 텍스트 필드가 있는 경우 텍스트 필드가 서로 겹치는 방식으로 iframe을 배치할 수 있음
- 따라서 방문자가 페이지에 표시되는 입력에 집중하려고 하면 실제로는 iframe 내부의 입력에 집중하게 됨
- 그런데 iframe이 표시되지 않기 때문에 방문자가 입력하는 모든 내용은 숨겨짐
- 사람들은 일반적으로 화면에 새 문자가 인쇄되는 것을 볼 수 없으면 입력을 중단
Old-school defences (weak)
1
2
3
if (top != window) {
top.location = window.location;
}
- 가장 오래된 방어 수단은 프레임에서 페이지를 여는 것을 금지하는(소위 framebusting) 약간의 자바스크립트
- 즉, 창에서 자신이 맨 위에 있지 않다는 사실을 알게 되면 자동으로 맨 위가 됨
- 해킹할 수 있는 방법이 많기 때문에 신뢰할 수 있는 방어가 아님
Blocking top-navigation
1
2
3
window.onbeforeunload = function () {
return false;
};
beforeunload
이벤트 핸들러에서top.location
변경으로 인한 전환을 차단할 수 있음- 최상위 페이지(해커가 속한 페이지)는 다음과 같이 방지 핸들러를 설정
- iframe이
top.location
변경을 시도하면, 방문자는 떠날 것인지 묻는 메시지를 받음 - 대부분의 경우 방문자는 iframe에 대해 모르기 때문에 부정적으로 대답
- 방문자가 볼 수 있는 것은 상단 페이지 뿐이므로 떠날 이유가 없음
- 그러니
top.location
은 변하지 않을 것
Sandbox attribute
1
<iframe sandbox="allow-scripts allow-forms" src="facebook.html"></iframe>
sandbox
속성에 의해 제한되는 것 중 하나는 navigation- 샌드박스가 적용된 iframe은
top.location
을 변경하지 않을 것 - 따라서 iframe에
sandbox="allow-scripts allow-forms"
를 추가할 수 있음 - 그러면 제한이 완회되어 스크립트와 폼이 허용됨
- 그러나 우리는
allow-top-navigation
을 생략하기 때문에top.location
을 변경하는 것은 금지됨
X-Frame-Options
- 서버 측
X-Frame-Options
헤더는 프레임 내부의 페이지 표시를 허용하거나 금지할 수 있음 - 이는 정확히 HTTP 헤더로 전송되어야 함
- 브라우저는 HTML
<meta>
태그에 있는 경우 이를 무시 - 그러니
<meta http-equiv="X-Frame-Options"...>
는 아무것도 하지 않을 것임 - 헤더에는 3가지 값이 있을 수 있음
DENY
: 절대로 프레임 않에 페이지를 표시하지 마세요SAMEORIGIN
: 상위 문서가 동일한 출처에서 나온 경우 프레임 내부를 허용ALLOW-FROM domain
: 상위 문서가 지정된 도메인의 문서인 경우 프레임 내부를 허용- 예를 들어 트위터는
X-Frame-Options: SAMEORIGIN
를 사용
- 예를 들어 트위터는
1
<iframe src="https://twitter.com"></iframe>
- 브라우저에 따라 위의 iframe은 비어있거나 해당 페이지를 이러한 방식으로 탐색하는 것을 허용하지 않는다는 경고 메시지를 표시
Showing with disabled functionality
X-Frame-Options
에는 부작용이 있음- 다른 사이트에서는 합당한 이유가 있더라도 우리 페이지를 프레임에 표시할 수 없음
- 그래서 다른 해결책이 있음
- 예를 들어 페이지를 스타일
height: 100%; width: 100%;
<div>
를 사용해 덮어 모든 클릭을 차단할 수 있음 window == top
이거나 보호가 필요하지 않다고 판단되면<div>
를 제거해야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
<div id="protector">
<a href="/" target="_blank">Go to the site</a>
</div>
<script>
// there will be an error if top window is from the different origin
// but that's ok here
if (top.document.domain == document.domain) {
protector.remove();
}
</script>
Samesite cookie attribute
1
Set-Cookie: authorization=secret; samesite
samesite
쿠키 속성은 클릭재킹 공격도 방지 가능- 이러한 속성을 가진 쿠키는 프레임 등을 통하지 않고 웹 사이트가 직접 열리는 경우에만 웹 사이트로 전송됨
- Facebook과 같은 사이트는 인증 쿠키에
samesite
속성을 가짐 - 그러면 Facebook이 다른 사이트의 iframe에서 열려 있을 때 해당 쿠키가 전송되지 않고 공격은 실패함
samesite
쿠키 속성은 쿠키가 사용되지 않으면 영향을 끼치지 않음- 이를 통해 다른 웹 사이트에서 iframe에 인증되지 않은 공개 페이지를 쉽게 표시할 수 있음
- 그러나 이로 인해 몇 가지 제한된 경우에 클릭재킹 공격이 작동할 수 있음
- 예를 들어 IP 주소를 확인하여 중복 투표를 방지하는 익명 투표 웹 사이트
- 쿠키를 사용해 사용자를 인증하지 않기 때문에 여전히 클릭재킹에 취약할 수 있음