sanitize-html를 사용해보자

권태형·2023년 2월 24일
0

이집은

목록 보기
5/12
post-thumbnail
post-custom-banner

이집은 프로젝트를 진행하면서 API보안에 대해서 더 많이 생각하게 되었다.

특히 XSS(크로스 사이트 스트립팅)공격에 대한 방어를 하기 위해서 어떻게 해야할까?를 고민하였는데, helmet라이브러리를 사용하여도 X-XSS-Protection Header가 0 값으로 비활성화가 고정된 값이며, 활성화로 변경할 수 없다는 점을 알게 되어, 따로 XSS공격에 대비하여 <Script>태그가 들어오지 못하도록 설정할 필요성이 생겼다.

구글링을 해본 결과 sanitize-html이라는 간단한 라이브러리를 사용하여 사용자 입력창에서 들어오는 일부 태그들을 걸러내는 방법을 알게되어 적용하게 되었다.

Sanitize-html란?

sanitize말 그대로 '소독하다' 라는 의미를 가진 들어오는 값을 중간과정에서 소독하는 역할을 하는 함수를 끌어다 쓸 수 있는 라이브러리이다.
사용자 입력값을 보내는 API요청에서 그 입력값에 적절하지 않는 <>태그가 존재했을 때 이를 제거해 주고 나머지 부분만 정상적인 데이터로 보내주는 역할을 해준다.

Sanitize-html의 동작순서

1.HTML 파싱
sanitize-html은 입력된 HTML 문자열을 파싱하기 위해 HTML 파서를 사용합니다. 이 파서는 입력된 문자열을 HTML 요소, 속성, 텍스트 노드 등의 노드로 분리합니다.

2.노드에 대한 필터링
sanitize-html은 각 노드의 타입과 속성을 분석하여, 안전하지 않은 요소나 속성을 필터링한다. 예를 들어, 스크립트 태그나 링크 태그의 href 속성은 보안 상의 이유로 필터링된다.

3.안전한 HTML 코드 생성
sanitize-html은 HTML 요소와 속성을 필터링한 후, 안전한 HTML 코드로 변환하는 과정을 진행한다. 이때 안전한 HTML 코드는 기본적으로 HTML5 스펙을 따르며, 사용자 지정 옵션을 통해 필요한 요소와 속성을 추가하거나 제거할 수 있다.

Sanitize-html 사용방법

npm i sanitize-html

위의 명령어로 라이브러리를 설치하고 import해 온 후 아래와 같이 사용할 수 있다

const clean = sanitizeHtml(dirty, {
  allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
  allowedAttributes: {
    'a': [ 'href' ]
  },
  allowedIframeHostnames: ['www.youtube.com']
});

snaitizeHtml이라는 함수의 첫번재 값은 들어오는 데이터 즉 res.body나 기타 등등이 될 수 있다. 이 dirty데이터를 2번째 인자인 옵션값으로 검증?하고 clean이라는 변수에 담는다.

위와 같이 직접적으로 일부 태그들을 개인설정 할 수 있으나, 기본적으로 2번째 인자 없이 1번째 인자만 활용할 경우 기본값으로 적용한다.

기본값은 sanitize-html 깃허브를 참고하자

기본값에 특정태그 추가하는 방법

기본태그를 유지하면서 일부 원하는 태그를 추가하고 싶을땐 아래와 같이 작성하면 된다.

const clean = sanitize(dirty, {
    allowedTags: sanitize.defaults.allowedTags.concat(['img']),
  });

미들웨어로 만들어서 사용해 보자

필자는 아래와 같이 미들웨어로 만들어 뽑아 썻다.

const sanitize = require('sanitize-html');

exports.postSanitizer = (req, res, next) => {
  const title = sanitize(req.body.title);
  const content = sanitize(req.body.content, {
    allowedTags: sanitize.defaults.allowedTags.concat(['img']),
  });
  const postLocation1 = sanitize(req.body.postLocation1);
  const postLocation2 = sanitize(req.body.postLocation2);
  req.filtered = { title, content, postLocation1, postLocation2 };
  next();
};
//API라우터 게시글 작성
postRouter.post(
  '',
  isLoggedIn,
  postCUDApiLimiter,
  multerPostImage.single('postImage'),
  postSanitizer,  //<<<<<< sanitize-html로 작성한 미들웨어 사용
  postController.createPost,
);

기능을 만드는데 급급해서 첫번째 인자로 받을 수 있는 값이 한정적이라 하나씩 나눠서 일일이 살균한 후에 req.filtered에 담아서 사용하였다.

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.
post-custom-banner

0개의 댓글