XSS
Cross-Site Scripting · 크로스 사이트 스크립팅
는 신뢰할 수 없는 값이 브라우저에서 실행 가능한 HTML·스크립트 문맥으로 들어가는 취약점이다. 입력이 저장되었는지보다 어떤 출력 지점에서 어떤 파서가 해석하는지가 핵심이다.
밑줄 용어에 마우스를 올리거나, 키보드로 선택하거나, 터치하면 설명을 볼 수 있습니다.
01무엇이고, 어떤 일을 하나
- 입력 부터 위험한 까지 데이터 흐름을 추적한다.
- HTML·속성·URL·스크립트 문맥에 맞는 출력 방어를 선택한다.
- 저장형·반사형·DOM 기반 경로를 구분해 재현 조건을 정한다.
02어떤 순서로 동작하나
- 값 획득
서버나 브라우저가 요청·저장 게시물·URL·API 응답 등에서 값을 읽는다.
- 출력 문맥 선택
값을 HTML 텍스트·속성·URL·스크립트 중 어디에 넣는지 결정한다. 문맥에 따라 필요한 처리가 달라진다.
- 안전한 자료 삽입
단순 표시는 textContent로 넣고, 허용된 HTML이 필요하면 정화된 구조를 사용한다.
- 브라우저 해석
innerHTML 같은 HTML 는 문자열을 요소 구조로 파싱한다. 실행 가능 여부는 실제 태그·속성·문맥과 정책에 달려 있다.
- 경로 검증
응답 원문·최종 DOM·실행 위치를 비교한다. 저장형은 저장 뒤 다른 조회에서도 같은 경로가 이어지는지 확인한다.
03먼저 알아둘 용어와 구성요소
- 주소·메시지·응답 등 외부 데이터가 시작되는 지점.
- innerHTML 등 데이터가 해석되거나 실행되는 출력 지점.
- 현재 파서에서 문법으로 쓰이는 문자를 데이터로 표현하는 처리.
- 허용한 HTML 구조를 남기고 위험한 요소·속성을 제거하는 처리.
- 저장된 입력이 다른 요청의 출력에서 실행되는 경로.
- 요청 입력이 같은 응답에 반영되어 실행되는 경로.
- 브라우저 측 코드의 자료 흐름에서 위험한 출력 해석이 일어나는 경로.
- Content Security Policy; 브라우저가 허용할 자원·실행 정책을 제한하는 방어층.
반사 입력과 저장된 DOM을 서로 다른 경로로 읽기
브라우저 화면·DOM·저장 시점을 구분해 의 와 를 설명한다.
실습 구성과 전제
- 자기 격리 에서 실제 계정 정보가 없는 전용 브라우저를 사용한다.
- 아래 Reflected 페이지와 Stored 페이지는 서로 다른 과제 화면이므로 한 번의 실행 순서로 합치지 않는다.
입력이 어디서 화면으로 돌아오는지 찾는다
- Reflected 과제에서는 폼 입력이 현재 응답에 반영되는 경로를 본다. 먼저 lab-marker 같은 무해한 문자열로 화면에 나타나는 위치를 기록한다.
- 표시됐다는 사실만으로 코드 실행을 확정하지 않는다. HTML 소스와 DOM에서 텍스트인지 요소인지 확인한다.
원본 크기로 보기 ↗- 제목은 Reflected Cross Site Scripting이며 이름 입력칸과 Hello 출력 위치가 보인다.
- 왼쪽에 Stored와 DOM 과제가 별도로 있어 유형이 다른 실습임을 구분할 수 있다.
확인 기준현재 요청과 응답에서 입력이 반영되는 위치를 특정한다.
저장 폼과 DOM의 실행 문맥을 확인한다
- Stored 과제에서는 입력이 저장된 뒤 다른 조회에서도 다시 렌더링되는지 본다. 재방문에 나타나는 것과 스크립트로 실행되는 것은 별도로 기록한다.
- textarea의 maxlength 같은 브라우저 조건은 서버 출력 인코딩을 대신하지 않는다. 최종 가 HTML·속성·스크립트 중 무엇인지 결정해야 한다.
원본 크기로 보기 ↗- DOM에 Stored Cross Site Scripting 제목과 POST guestform이 표시된다.
- mtxMessage textarea의 maxlength가 1000으로 보인다. 길이 제한이 있어도 출력 문맥 처리가 필요하다.
확인 기준저장 여부·출력 위치·실행 여부를 세 항목으로 나눈다.
텍스트 출력으로 같은 입력을 비교한다
- 허용된 HTML이 필요하지 않은 영역은 textContent나 문맥에 맞는 출력 인코딩을 사용한다. HTML을 허용해야 한다면 정화 정책을 별도로 설계한다.
- 문자열 '<b>lab</b>'를 예로 들어 요소로 렌더링하는 출력과 그대로 글자로 표시하는 출력을 비교한다.
const value = '<b>lab</b>'; output.textContent = value;교육용 DOM 비교 예시. 입력을 코드로 실행하지 않고 글자로 표시한다.
확인 기준수정 후에는 정상 글자가 사라지지 않으면서 데이터가 실행 문맥을 만들지 않아야 한다.
실습에서 확인한 동작 원리
- 반사·저장·DOM 경로는 입력의 이동 방식과 실행 시점을 나누는 기준이다.
- 실제 방어는 최종 출력 문맥에 맞춰 적용한다.
04예제로 따라가기
- 요구 정의: 사용자가 입력한 제목은 A&B <C>라는 텍스트이며 태그나 엔터티 기능을 의도하지 않았다고 가정한다.
- 텍스트 API: div 같은 일반 요소의 textContent에 원래 값을 넣으면 텍스트 노드가 되어 <C>가 HTML 요소로 파싱되지 않는다. script·style 요소에 신뢰할 수 없는 내용을 넣는 경우에 이 설명을 적용하면 안 된다.
- HTML 문자열: 서버가 HTML 본문 문자열을 생성하는 경우 A&B <C>처럼 해당 문맥에 맞게 표현한다.
- 파싱 결과: HTML 파서는 엔터티를 문자로 해석하여 화면에 A&B <C>를 보여 준다. 엔터티가 풀렸다고 입력을 다시 HTML 코드로 실행하는 것은 아니다.
- 이중 처리: 이미 인코딩된 &를 다시 인코딩하면 &amp;가 되어 화면에 &가 남을 수 있다. 저장 형식과 출력 변환의 책임을 구분한다.
05혼동하기 쉬운 점과 확인 기준
- 입력 출처: URL fragment·브라우저 저장소·메시지 이벤트처럼 서버 응답에 직접 나타나지 않는 를 추적한다.
- 값의 변형: 디코딩·문자열 연결·템플릿 렌더링을 거쳐 어느 에 도달했는지 본다. 최종 화면만 보아서는 최초 입력 경로를 알기 어렵다.
- 문맥 변화: HTML 텍스트용 인코딩을 ·CSS 문자열에도 공통 적용하지 않는다. 코드 문맥에 외부 값을 삽입하는 설계부터 줄인다.
06상세 노트 · 실습 자료
헤더 구조, 설정 예시, 수치 계산과 수업 캡처는 아래 노트에서 이어집니다.
함께 보는 학습 자료
아래 공식 자료를 본문의 개념·예제와 함께 읽어 보세요. 자료별로 확인할 위치와 관찰할 내용을 적었습니다.
OWASP: HTML·속성·DOM 출력 문맥 비교
같은 입력도 삽입되는 파서 문맥에 따라 방어가 달라진다는 점을 예제별로 비교할 수 있다.
- 일반 요소 textContent와 HTML 문자열 인코딩의 차이
- 따옴표 있는 속성과 이벤트 처리기 속성의 차이
- HTML·URL· 문맥에 필요한 별도 통제
공식 문서 · 표준
기초 개념과 동작 설명을 대조한 자료입니다. 제품 버전과 실제 설정에 따른 차이는 본문 및 원문에서 확인하세요.