XSS (Cross-Site Scripting) 이란?
가장 널리 알려진 웹 보안 취약점 중 하나입니다.
악의적인 사용자가 공격하려는 사이트에 악성 스크립트를 삽입할 수 있는 보안 취약점입니다.
XSS를 통해 악성 코드를 제어하는 사이트로 리다이렉트 하거나, 사용자의 쿠키를 탈취하여 세션 하이재킹 공격을 할 수 있습니다.
대표적인 공격 방식은 다음과 같습니다.
- Stored XSS
- Reflected XSS
- DOM Based XSS
DOM based XSS
DOM 기반 XSS 공격은 보안에 취약한 JavaScript 코드로 DOM 객체를 제어하는 과정에서 발생합니다.
DOM based XSS 공격 시나리오
- 악의적인 사용자가 보안이 취약한 사이트를 발견했습니다.
- 보안이 취약한 웹 페이지에서 악성 스크립트가 실행되도록 URL 주소를 만들어 일반 사용자에게 전달합니다.
- 일반 사용자는 메일을 통해 전달받은 URL 링크를 클릭합니다. 서버로 부터 HTML 문서를 전달 받습니다.
- 사용자의 브라우저가 응답 받은 HTML 문서를 읽으면서 필요한 스크립트를 실행하는 중에 악성 스크립트가 동작합니다.
- 악성 스크립트를 통해 사용자의 정보가 악의적인 사용자에게 전달됩니다.
DOM based XSS 공격 시연
1. 다음과 같은 사이트가 있습니다.
2. 링크를 누르면 href 를 통해 악성 스크립트가 심어진 url 을 얻게됩니다.
3. 해당 사이트는 url 을 파싱하여 innerHTML 에 삽입하는 코드를 사용하고 있습니다.
function append_content(content) {
document.getElementById("raw").innerHTML += content;
document.getElementById("escaped").innerHTML += escape(content);
document.getElementById("encoded").innerHTML += encodeURI(content);
}
4. 위 취약점 코드로 공격이 시도됩니다.
DOM Based XSS 공격 과 Reflected XSS 공격의 차이점?
이 글을 쓰기전에 Reflected XSS 을 복습했는데, 두 공격이 유사해보입니다.
똑같은거 아님?
어떤 차이점이 있을까요?
Reflected XSS
Relfected XSS 는 서버측에서 사용자 입력값을 응답에 실어서 보냅니다.
저는 바보라서 텍스트만 보면 이해를 잘 못합니다. 시각자료를 봅시다.
위 처럼 사용자의 입력 값이 서버에 응답에 포함되어 온 것을 확인할 수 있습니다.
즉, 악성스크립트가 담겨서 응답으로 오게됩니다.
DOM Based XSS
반면에 DOM Based XSS 은 클라이언트단에서 DOM 을 JS 로 조작하여 악성스크립트를 실행하는 것 입니다.
정리하자면,
- Reflected XSS 은 해커가 입력한 스크립트가 서버로 전달되어, 악성스크립트가 심어저 있는 비정상적인 HTML 문서를 전달 받게 됩니다.
- DOM Based XSS 는 정상적인 HTML 문서를 전달 받지만, 취약점을 클라이언트단에서 JS 를 통해 조작하여 악성스크립트를 실행하는 것을 의미합니다.
DOM Based XSS 방어
그럼 어떻게 방어해야할까요?
1. innerHTML 지양하기
innerHTML은 XSS 공격에 취약합니다.
따라서 다음과 같이 innerHTML 을 사용하는 코드는 지양하고 innerText 나 textContent 를 사용하는 것이 좋습니다.
function append_content(content) {
document.getElementById("raw").innerHTML += content;
document.getElementById("escaped").innerHTML += escape(content);
document.getElementById("encoded").innerHTML += encodeURI(content);
}
innerText 와 textContent 의 차이?
innerText 는 말 그대로 Text 만 얻을 수 있고, textContent 는 <style> 태그의 정보와 같은 데이터를 텍스트와 함께 얻을 수 있습니다.
2. HTML 새니티제이션
하지만 innerHTML 을 사용해야할 수도 있지않습니까?
이때 HTML 새니티제이션을 사용해보는 건 어떨까요?
function append_content(content) {
document.getElementById("raw").innerHTML += DOMPurify.sanitize(content);
document.getElementById("escaped").innerHTML += DOMPurify.sanitize(
escape(content)
);
document.getElementById("encoded").innerHTML += DOMPurify.sanitize(
encodeURI(content)
);
}
새니티제이션을 사용하면 시나리오에서 실행된 것과는 달리 스크립트가 실행되지 않은 것을 확인할 수 있습니다.
3. URL 을 직접사용하는 코드 지양하기.
URL에는 쿼리스트링을 사용할 수도있고, 여러 정보를 담을 수 있는데 이러한 URL 정보를 바로 innerHTML과 XSS 공격 위험이 있을 수 있는 코드에 바로 사용하는 것을 지양함으로써 취약점이 있는 코드를 작성하는 것을 막을 수 있습니다.
Test Code Repo
https://github.com/nleach999/DOM-XSS-JS-Example
참고자료
1. https://junhyunny.github.io/information/security/dom-based-cross-site-scripting/
2. https://www.inflearn.com/questions/821122/dom%EA%B3%BC-reflected-xss-%EC%B0%A8%EC%9D%B4
3. https://www.acunetix.com/blog/web-security-zone/how-to-prevent-dom-based-cross-site-scripting/
4. 모던 자바스크립트 딥 다이브
'CS > 네트워크 & 웹' 카테고리의 다른 글
CSRF (Cross-Site Request Forgery) 공격과 방어 (0) | 2023.04.23 |
---|---|
저장형(Stored) XSS(Cross-Site Scripting) 공격과 방어 (0) | 2023.04.14 |
반사형(Reflected) XSS(Cross-Site Scripting) 공격과 방어 (2) | 2023.04.13 |
토큰을 어디에 저장해야할까요? (4) | 2023.04.13 |
Transfer-Encoding: Chunked (0) | 2023.04.11 |