flawopen.com/크로스 사이트 스크립팅
크로스 사이트 스크립팅
크로스 사이트 스크립팅은 페이지가 한 사용자의 글을 브라우저가 HTML이나 JavaScript로 파싱하는 방식으로 포함할 때, 그 글이 사이트 자신의 권한으로 다른 사용자에게서 실행되면서 발생합니다. 해결책은 어디서나 같습니다. 값이 쓰이는 정확한 위치에 맞게 모든 값을 인코딩하고, HTML을 허용해야 하는 드문 필드는 새니타이즈하며, 둘 다 Content Security Policy로 뒷받침하는 것입니다. 아래에서 언어를 고르면 정확한 API, 취약한 코드와 수정한 코드, CI에서 이를 잡아내는 규칙을 볼 수 있습니다.
알기 쉬운 설명 (ELI5)
신문사는 독자 투고를 자기 지면에 싣습니다. 한 독자가 편집부 공지와 똑같이 편집된 투고를 보냅니다. '구독자 여러분, 갱신하려면 이 번호로 전화해 카드 정보를 불러 주세요.' 신문의 서체로 인쇄되어 있으니 독자들은 편집부가 쓴 글처럼 믿습니다. XSS는 웹사이트가 방문자의 글을 자기 페이지에 그대로 찍어 내고, 브라우저가 그것을 사이트 자신의 코드로 여겨 사이트가 가진 계정 접근 권한으로 실행하는 것입니다. 이스케이프는 모든 투고를 뚜렷하게 표시된 인용 상자 안에 인쇄해서, 어떤 투고도 편집부 공지로 행세하지 못하게 하는 것입니다.
핵심 개념 및 용어
- Cross-site scripting (CWE-79)
- 웹 페이지가 신뢰할 수 없는 데이터를 브라우저용으로 무력화하지 않고 포함해서, 그 데이터 속 마크업이나 스크립트가 페이지의 출처에서 파싱·실행되고 DOM, 쿠키, API에 접근합니다.
- Reflected, stored and DOM-based XSS
- 반사형 XSS는 요청 데이터를 응답에 그대로 돌려주며, 보통 조작한 링크를 통해 일어납니다. 저장형 XSS는 값을 저장해 모든 열람자에게 제공합니다. DOM 기반 XSS는 서버를 거치지도 않습니다. 클라이언트 JavaScript가 URL이나 저장소의 데이터를
innerHTML같은 싱크로 복사합니다. - Contextual output encoding
- 출력 문맥마다 고유한 인코딩이 필요합니다. 요소 텍스트와 따옴표 속성에는 HTML 엔터티, 스크립트 안에서는 JavaScript 문자열 이스케이프, URL 파라미터에는 퍼센트 인코딩,
href와src에는 스킴 검사가 필요합니다. 스크립트 안에 넣는 값을 HTML 인코딩만 해서는 부족합니다. - Sanitizing vs encoding
- 인코딩은 마크업을 글자로 보여 줍니다. 사용자가 서식을 보내야 한다면 HTML을 허용 목록 새니타이저(DOMPurify, bleach의 후속인 nh3, OWASP Java HTML Sanitizer, HtmlSanitizer, ammonia)에 통과시켜 허용된 태그는 남기고 스크립트, 이벤트 핸들러,
javascript:URL은 제거합니다. - Content Security Policy (CSP)
- 어떤 스크립트를 실행해도 되는지 브라우저에 알려 주는 응답 헤더입니다. nonce 기반이며
'unsafe-inline'이 없는script-src는 인코딩 버그가 새어 나가도 주입된 스크립트 대부분을 막고,require-trusted-types-for 'script'는 DOM 싱크를 잠급니다.
단계별 공격 실행 흐름
신뢰할 수 없는 텍스트가 페이지에 도달
검색어, 프로필 필드, 댓글, URL 프래그먼트, API 응답이 서버에서 페이지를 만들 때나 브라우저에서 갱신할 때 포함됩니다.
올바른 인코딩 없이 쓰임
템플릿 이스케이프가 꺼져 있거나, 값이 HTML 이스케이프로 다루지 못하는 스크립트나 URL 문맥에 들어가거나, 클라이언트 코드가 그것을 innerHTML에 대입합니다. 무해한 테스트 값 <img src=x onerror=alert(1)>가 그대로 살아남습니다.
브라우저가 그것을 코드로 파싱
피해자의 브라우저가 실제 <img> 요소를 만들어 onerror를 발생시키거나, 클릭하면 javascript: 링크를 실행합니다.
스크립트가 사이트로서 행동
사이트의 출처로 실행되어 페이지를 읽고, 피해자의 쿠키나 토큰으로 사이트 API를 호출하며, 사용자가 보는 내용을 바꾸고, 사용자 대신 폼을 제출할 수 있습니다.
언어별 XSS 가이드
엔지니어링 및 시스템 보안 강화 체크리스트
- 모든 페이지를 자동 이스케이프가 켜진 템플릿 엔진으로 렌더링하고, 모든 예외(
|safe,Html.Raw,dangerouslySetInnerHTML,raw,unsafe { },{!! !!})를 검토합니다. - 정확한 문맥에 맞게 인코딩합니다. HTML 텍스트와 따옴표 속성, JavaScript 문자열, URL 파라미터를 구분하고, 문자열 연결로 HTML이나 JavaScript를 만들지 않습니다.
- 사용자가 준 HTML은 렌더링하는 지점에서 관리되는 허용 목록 새니타이저로 정리합니다.
- 사용자가 준 URL은
href,src, 페이지 이동에 닿기 전에http와https만 허용합니다. - nonce 기반이며
'unsafe-inline'이 없는 Content-Security-Policy와X-Content-Type-Options: nosniff를 보냅니다. - 세션 토큰은
localStorage가 아니라HttpOnly,Secure,SameSite=Lax쿠키에 둡니다.