이집은 프로젝트를 진행하면서 API보안에 대해서 더 많이 생각하게 되었다.
특히 XSS(크로스 사이트 스트립팅)공격에 대한 방어를 하기 위해서 어떻게 해야할까?를 고민하였는데, helmet라이브러리를 사용하여도 X-XSS-Protection Header가 0 값으로 비활성화가 고정된 값이며, 활성화로 변경할 수 없다는 점을 알게 되어, 따로 XSS공격에 대비하여 <Script>
태그가 들어오지 못하도록 설정할 필요성이 생겼다.
구글링을 해본 결과 sanitize-html이라는 간단한 라이브러리를 사용하여 사용자 입력창에서 들어오는 일부 태그들을 걸러내는 방법을 알게되어 적용하게 되었다.
sanitize
말 그대로 '소독하다'
라는 의미를 가진 들어오는 값을 중간과정에서 소독하는 역할을 하는 함수를 끌어다 쓸 수 있는 라이브러리이다.
사용자 입력값을 보내는 API요청에서 그 입력값에 적절하지 않는 <>
태그가 존재했을 때 이를 제거해 주고 나머지 부분만 정상적인 데이터로 보내주는 역할을 해준다.
1.HTML 파싱
sanitize-html은 입력된 HTML 문자열을 파싱하기 위해 HTML 파서를 사용합니다. 이 파서는 입력된 문자열을 HTML 요소, 속성, 텍스트 노드 등의 노드로 분리합니다.
2.노드에 대한 필터링
sanitize-html은 각 노드의 타입과 속성을 분석하여, 안전하지 않은 요소나 속성을 필터링한다. 예를 들어, 스크립트 태그나 링크 태그의 href 속성은 보안 상의 이유로 필터링된다.
3.안전한 HTML 코드 생성
sanitize-html은 HTML 요소와 속성을 필터링한 후, 안전한 HTML 코드로 변환하는 과정을 진행한다. 이때 안전한 HTML 코드는 기본적으로 HTML5 스펙을 따르며, 사용자 지정 옵션을 통해 필요한 요소와 속성을 추가하거나 제거할 수 있다.
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에 담아서 사용하였다.