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일을 고생함 ㅠㅠㅠㅠㅠ
'프론트엔드 개발자로 일하기' 카테고리의 다른 글
보고 또 봐도 또 모르는 cors (0) | 2024.09.17 |
---|---|
이벤트 버블링, 이벤트 캡처링 (0) | 2024.09.17 |
thymeleaf에서 fragment로 vue 컴포넌트 만들기 (0) | 2024.09.03 |
이슈 트래킹 - lazy loading (2) | 2024.09.01 |
후루룹 말아먹고 써보는 github 이야기.. (0) | 2024.09.01 |