프론트엔드 개발자로 일하기

tui-editor 에서 customHTMLSanitizer 커스텀해서 사용하기

프론트루나 2024. 9. 10. 08:07
반응형

TUI Editor 는 마크다운 기반의 웹 에디터로, 다양한 기능을 제공하며 사용자 정의가 용이한 오픈소스 프로젝트이다.

특히 HTML을 입력하거나 렌더링할때 보안 및 UX를 고려해 HTML을 필터링하는 기능을 제공하는데, 이 기능이 customHTMLSanitizer이다. HTML의 불필요하거나 잠재적인 보안 위협 요소를 제거하는 작업을 수행한다.

기본적으로 내장된 HTMLSanitizer를 사용하지만, 특정 태그나 속성을 허용하고 싶다면 customHTMLSanitizer 옵션을 통해 이를 커스터마이징 할 수 있다.

기본설정

TUI editor를 사용할때, customHTMLSanitizer 옵션을 설정하지않으면, 기본적으로 DOMPurify라이브러리가 내부적으로 사용된다.

해당 라이브러리는 안전하지 않은 태그나 속성을 제거하여 XSS(Cross-Site-Scripting) 공격을 방지한다.

const editor = new toastui.Editor({
    el : document.querySelector("#editor"), 
    height : '500px',
    ... 
    cumstomHTMLSanitizer : function(html) {
        return DOMPurify.sanitize(html);
    }
})

커스터마이징하기

에디터에서 특정 태그나 속성을 허용하거나 필터링 규칙을 조정할 수 있는 기능을 제공한다.
예를 들어, iframe 태그와 같은 특정 태그를 허용하거나, 모든 img태그에 loading=lazy 속성을 추가하려면 커스터마이징하면 된다.

const editor = new toastui.Editor({
  el: document.querySelector('#editor'),
  height: '500px',
  initialEditType: 'markdown',
  previewStyle: 'vertical',
  customHTMLSanitizer: function(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');

    // 모든 iframe 태그를 찾고 제거하지 않음
    const iframes = doc.querySelectorAll('iframe');
    iframes.forEach(iframe => {
      // 필요한 속성만 남기고 나머지 속성을 제거하거나 조정 가능
      iframe.setAttribute('width', '560');
      iframe.setAttribute('height', '315');
      iframe.setAttribute('allowfullscreen', '');
    });

    return doc.body.innerHTML;
  }
});

위 예제에서는 DOMParser를 사용해 입력된 HTML을 파싱한 뒤, <iframe> 태그를 찾아 크기나 속성을 수정하고 그대로 남긴다.

이처럼 사용자가 원하는 대로 특정 태그나 속성을 허용하거나 수정할 수 있다.

📍보안 고려사항

customHTMLSanitizer를 사용하여 특정 태그나 속성을 허용할 때는 보안에 주의해야 한다. 특히 iframe 태그나 사용자 입력을 직접 HTML로 렌더링하는 경우, XSS 공격이 발생할 수 있으므로 신뢰할 수 없는 콘텐츠에 대해서는 충분한 검증 절차를 거치는 것이 중요하다.

또한, 외부 라이브러리인 DOMPurify를 적절히 활용하여 커스터마이징할 수 있으며, 이를 통해 불필요한 스크립트나 인라인 이벤트를 자동으로 제거할 수 있습니다.

  const editor = new toastui.Editor({
  el: document.querySelector('#editor'),
  height: '500px',
  initialEditType: 'markdown',
  previewStyle: 'vertical',
  customHTMLSanitizer: function(html) {
    // DOMPurify 사용하여 기본적인 보안 처리
    let cleanHTML = DOMPurify.sanitize(html);

    // 추가적으로 <iframe> 태그는 허용
    const parser = new DOMParser();
    const doc = parser.parseFromString(cleanHTML, 'text/html');
    const iframes = doc.querySelectorAll('iframe');

    iframes.forEach(iframe => {
      iframe.setAttribute('width', '560');
      iframe.setAttribute('height', '315');
      iframe.setAttribute('allowfullscreen', '');
    });

    return doc.body.innerHTML;
  }
});

기본적인 필터링은 DOMPurify에 맡기고, 추가적인 수정 작업만 직접 처리하는 방식으로 보안성과 커스터마이징 사이에서 균형을 잡을 수 있다.

 


📓 issue-tracking

현상

- 컬러피커 플러그인을 추가하고, span태그에 스타일 속성을 입힌 태그가 제거된 채 렌더링되는 현상 

- 문자열을 선택하고 컬러피커를 적용했을때 콘솔에 null 속성에 접근 불가하다는 로그가 뜨며 진행되지않고 텍스트는 ""로 치환되는 현상

 

solve

customHTMLSanitizer: html => {
        return DOMPurify.sanitize(html, {
            ALLOWED_TAGS: ['p','b', 'i', 'em', 'strong', 'a', 'span'], // 허용할 태그
            ALLOWED_ATTR: ['href', 'target', 'rel', 'style', 'class'],
            ALLOW_UNKNOWN_PROTOCOLS: true,  // 사용자 정의 URL 프로토콜 허용
            SANITIZE_URL: false             // URL 필터링 비활성화
        })
    }

 

ALLOW_TAGS 에 span 태그를 허용하고, ALLOWED_ATTR 허용할 속성에 style, class 속성을 추가한다. 

 

ㅠㅠ 이거 찾는다고 3일을 고생함 ㅠㅠㅠㅠㅠ

 

반응형