TIL #74 | dangerouslySetInnerHTML를 사용할 때의 위험성?

kibi·2024년 1월 30일
0

TIL (Today I Learned)

목록 보기
74/83

지금 진행하고 있는 프로젝트에서 텍스트 에디터로 작성한 글을 리스트에서 태그 없이 보여주기 위해 dangerouslySetInnerHTML을 사용하고 있었다.
dangeouslySetInnerHTML? 말 그대로 하면 innerHTML을 위험하게 설정한다 라는 뜻인데... 사용하면서 이런 이름이 지어진 이유가 궁금했고, innerHTML을 사용할 때의 문제점에 대해서도 알아보고 싶어졌다.


🤔 일단 공식문서에 따르면...

dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법입니다. 일반적으로 코드에서 HTML을 설정하는 것은 사이트 간 스크립팅 공격에 쉽게 노출될 수 있기 때문에 위험합니다. 따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 작성하고 __html 키로 객체를 전달해야 합니다.

출처: https://ko.legacy.reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

일반적으로 innerHTML을 사용하여 직접 HTML을 설정하는 것은 사이트 간 스크립팅 공격 즉, "XSS(Cross-Site Scripting) 공격"에 취약하기 때문에 위험성을 상기시켜주기 위해 dangerouslySetInnerHTML을 작성하는 것이라고 한다.

나의 경우 아래와 같이 코드를 작성했는데 나도 모르게 위험성이 있는 코드를 작성하고 있었던 것이었다...!

dangerouslySetInnerHTML={{ __html: content }}

그래서 XXS 공격을 통해 일어나는 문제점은 뭘까?
좀 더 자세히 알아보자.

XSS 공격?

크로스 사이트 스크립팅 또는 교차 사이트 스크립팅(Cross Site Scripting, XSS)은 공격자가 상대방의 브라우저에 스크립트가 실행되도록 해 사용자의 세션을 가로채거나, 웹사이트를 변조하거나, 악의적 콘텐츠를 삽입하거나, 피싱 공격을 진행하는 것을 말합니다. XSS 공격은 스크립트 언어와 취약한 코드를 공격 대상으로 합니다.

출처: https://nordvpn.com/ko/blog/xss-attack/

누구나 HTML을 변경할 수 있게 되면 악의적인 코드를 심어 문제를 야기할 수 있다는 것이다. 그렇다면 이런 문제의 해결책은 어떤 것이 있을지 조사해봤다.

innerHTML을 정제하여 사용하기 위해 대체적으로 2가지의 라이브러리를 사용하고 있는 것 같다.

XSS를 방지하기 위한 방법

1. sanitize-html

허용된 태그와 속성 외에 html 태그를 허용하지 못하도록 한다.
sanitize-html은 Node.js와 함께 사용하도록 고안되었으며 Node 10 이상을 지원한다. (브라우저에서의 사용도 지원하지만 서버에서의 사용을 권한다.)
출처: https://www.npmjs.com/package/sanitize-html?activeTab=readme


2. DOMPurity

DOM 레벨에서 HTML을 sanitize 해주고 XSS 공격을 막아준다
DOMPurify는 HTML을 삭제하고 XSS 공격을 방지합니다. 더티 HTML로 가득 찬 문자열을 DOMPurify에 제공할 수 있으며 달리 구성하지 않는 한 깨끗한 HTML이 포함된 문자열을 반환한다.
현재 19개의 다양한 브라우저를 다루고 있으며 앞으로 더 많은 브라우저가 포함될 예정이며 jsdom 에서 DOMPurify를 실행하는 Node.js v16.x, v17.x, v18.x 및 v19.x를 다룬다.
출처: https://github.com/cure53/DOMPurify


나는 현재 브라우저 상에서 라이브러리를 사용하고 있다는 이유와 패키지 다운로드 수가 높고 최근까지도 활발하게 업데이트 되고 있는 DOMPurity를 사용했다.
그렇지만 조사하는 김에 두 라이브러리의 사용방법을 같이 알아보았다.


DOMPurity 사용 방법

yarn add dompurify @types/dompurify

import DOMPurify from "dompurify"

https://github.com/cure53/DOMPurify 페이지에서 여러 가지 속성을 찾아 사용할 수 있다.
나는 모든 태그 및 속성을 없애고 싶었기 때문에 아래와 같이 태그와 속성 중 아무것도 허용하지 않는 코드로 작성했다.

dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content, { ALLOWED_TAGS: [], ALLOWED_ATTR: []}),

sanitize-html 사용 방법

yarn add sanitize-html @types/sanitize-html
"types": [
  "@types/sanitize-html" //추가
]
import sanitizeHtml from "sanitize-html"

allowedTags와 allowedAttributes 옵션을 false로 설정하면 모든 태그와 속성을 허용한다. 아래는 span 태그만을 허용할 때의 코드이다.

const cleaned = sanitizeHtml(content, {
  allowedTags: ["span"],
})
dangerouslySetInnerHTML={{ __html: cleaned }}

이번 조사를 통해 XXS 공격의 위험성에 대해 다시 한번 상기시키는 시간이 되었고, 좀 더 안전하게 dangerouslySetInnerHTML를 사용할 수 있는 방법에 대해서 알게 되었다.
적용할 수 있는 라이브러리의 사용 방법을 알아보았으니 필요에 따라 적절하게 골라서 사용하면 좋을 것 같다.

0개의 댓글