인젝션 - XSS
XSS라고도 하는 크로스 사이트 스크립팅은 다른 사용자의 브라우저에서 공격자가 제어하는 스크립트가 평가되도록 하는 또 다른 유형의 인젝션 취약점입니다. XSS는 HTML/JavaScript 인젝션 취약점이라고도 볼 수 있습니다.
XSS 취약점의 영향은 취약점이 존재하는 컨텍스트에 따라 크게 달라집니다. 스크립트가 실행되는 페이지에서 정보를 추출할 수 있는 것부터 페이지의 상태를 편집하여 페이지에서 피해자가 되어 작업을 수행할 수 있는 것까지 다양합니다.
발생할 수 있는 XSS의 유형을 살펴보겠습니다.
XSS 유형
XSS는 몇 가지 버킷으로 나누어 구분할 수 있습니다. 페이로드가 전달되는 방식과 진입 지점이 어디에 있는지에 따라 분류됩니다.
페이로드 전달 벡터(저장된 것과 반영된 것)
공격자가 XSS 페이로드를 전달하는 방법에는 두 가지가 있습니다:
- 저장된 XSS: 예를 들어 데이터베이스에 저장된 사용자 제어 데이터를 통해 다른 사용자에게 데이터가 렌더링됩니다.
- 반영된 XSS: 사용자가 탐색한 URL/쿼리 문자열을 통해 전달된 사용자 제공 페이로드를 통해.
중요한 차이점은 반영된 XSS는 일반적으로 사용자 상호 작용에 따라 달라지며 악성 페이로드가 포함된 링크를 연 사용자에게만 영향을 미친다는 점입니다. 그러나 저장된 XSS는 페이로드를 렌더링하는 일부 페이지를 열기만 해도 한 명 이상의 사용자를 대상으로 실행될 수 있습니다.
페이로드 위치(DOM 대 Non-DOM)
페이로드가 삽입되는 위치에 따라 해당 취약점을 "DOM" 취약점으로 분류할지 여부가 결정됩니다. 이는 페이로드가 렌더링되는 위치를 구분하는 것입니다:
- Non-DOM XSS: 페이로드가 태그 또는 어트리뷰트 등 HTML 내부에서 렌더링됩니다.
- DOM XSS: The payload is rendered inside JavaScript, like a `<script>` tag, or an event handler such as `onclick=""`
XSS - 방어 기본 요소
이 섹션에서는 XSS 방어의 기본이 되는 기본 원칙에 대해 살펴봅니다. 기본 사항을 이해하는 것은 필수적이지만 실제로는 템플릿 라이브러리에 의존해야 XSS로부터 99%를 보호할 수 있습니다.
브라우저에서 실행되는 마크업이나 코드로 렌더링되는 템플릿을 작성할 때 XSS로부터 보호하는 핵심은 *인코딩*입니다. 여기서 인코딩이란 일련의 문자를 가져와 인터프리터가 특정 방식으로 처리하는 형식으로 변경하는 것을 의미합니다.
그러나 사용할 인코딩 유형은 데이터가 사용되는 위치 또는 컨텍스트에 따라 달라집니다.
- Inside a tag, like `<div>User input here</div>`: **HTML Encoding**
- Inside an attribute, like `<input placeholder="User input here"></input>`: **Attribute Encoding**
- Inside Javascript, like `<script>x = "User input here";</script>`: **JavaScript Encoding**
일부 프레임워크는 인코딩을 주요 방어 수단으로 사용하지 않고 대신 살균을 사용하여 위험할 수 있는 모든 콘텐츠에서 값을 스크러빙합니다. 이는 고려해야 할 엣지 케이스가 많은 훨씬 더 복잡한 프로세스입니다. 자체적인 살균 루틴을 구현하는 것은 권장하지 않습니다.
예제
다양한 언어로 된 몇 가지 예시를 통해 실제로 어떤 모습인지 살펴보세요.
C# - 안전하지 않습니다: Razor
IHtmlContent` 객체 앞에 `@`가 붙으면 인코딩 없이 값이 템플릿에 직접 배치됩니다.
<!--- UNSAFE: The htmlSnippet will get interpreted without any escaping --->
@Html.Raw(htmlSnippet)
C# - 보안: Razor
기본적으로 `@`가 접두사로 붙은 모든 `스트링`은 Razor 템플릿에서 HTML 이스케이프 처리됩니다.
<!--- SAFE: The htmlSnippet will get HTML escaped --->
@htmlSnippet
Java - 보안: JSP
c:out`을 사용하면 기본적으로 XML 이스케이프(`escapeXml` 속성으로 변경 가능)가 적용되어 HTML 컨텍스트에서는 XSS를 방지하지만 다른 컨텍스트에서는 그렇지 않습니다.
<div><c:out value="<%= author %>" /></div>
Java - 보안: (fnxml)
위와 비슷하게 `fn:escapeXml`을 직접 호출하여 주어진 입력을 XML 이스케이프 처리할 수도 있습니다. 이 역시 HTML 컨텍스트에서만 보호됩니다.
<div>${fn:escapeXml(author)}</div>
자바스크립트 - 안전하지 않습니다: 앵귤러 내부Html
이름에서 알 수 있듯이 `innerHTML` 속성을 지정하면 출력 인코딩을 비활성화하여 XSS의 위험에 노출됩니다.
<!--- UNSAFE: The htmlSnippet will get interpreted without any encoding --->
<p [innerHTML]="htmlSnippet"></p>
자바스크립트 - 보안: 각도 보간
Angular에서 이중 중괄호(`{{` 및 `}}`)를 사용하여 텍스트를 보간하면 HTML이 출력을 이스케이프 처리하여 XSS로부터 보호합니다.
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<p>{{htmlSnippet}}</p>
자바스크립트 - 안전하지 않습니다: React 위험한InnerHtml
이름에서 알 수 있듯이 `dangerouslySetInnerHTML` 속성을 지정하면 출력 인코딩을 비활성화하여 XSS의 위험에 노출됩니다.
<!--- UNSAFE: As the name suggests, the dangerouslySetInnerHTML attribute is dangerous as it does not escape the output --->
<div dangerouslySetInnerHTML={{ __html: htmlSnippet }} />;
자바스크립트 - 보안: 리액트 보간
중괄호(`{` 및 `}`)를 사용하여 텍스트를 보간하는 React의 보간은 HTML이 출력을 이스케이프 처리하여 XSS로부터 보호합니다.
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<div>{htmlSnippet}</div>
Python - 안전하지 않습니다: Django
장고 템플릿에서 `safe` 필터를 사용하면 출력의 자동 이스케이프가 비활성화되어 XSS로부터 보호되지 않습니다.
<!--- UNSAFE: The htmlSnippet will not get HTML encoded --->
<div>{{ htmlSnippet | safe }}</div>
Python - 보안: Django
장고에서 이중 중괄호(`{{` 및 `}}`)를 사용하여 텍스트를 보간하면 HTML이 출력을 이스케이프 처리하여 XSS로부터 보호합니다.
<!--- SAFE: The htmlSnippet will HTML encoded --->
<div>{{ name }}</div>