정권 찌르기[리팩토링 6-8일차]: text editor 에러 개선 및 XSS 공격을 방지하기 위한 고민

밍구·2023년 7월 21일
0
post-thumbnail

롯데 e커머스 채용연계형 면접으로 보고와서 적는 리팩토링 글!
물론 떨어졌기에 큰 도움은 안되겠지만 내년에 면접 볼 분들을 위해 후기를 작성 할 생각이다.

💥 문제

5일차 포스팅에 문제에 대한 고민을 팀원들과 함께 의논을 해 본 결과..

ㅎㄱ 님: 노션은 드래그 앤 드랍과 엔터치면 새로운 블록 생성되는 기능 둘 다 있지 않나요..?

생각해보니 맞는 말이다. 그래서 둘 다 개발하는 걸로!
( 드래그 앤 드랍은 다음 포스팅에서 다룰 예정 입니다)

1. contentEditable 무한 렌더링 에러

-> 사실 리팩토링하면서 계속 에디터를 고도화 하기 위해 공부하는데
contentEditable 속성에 문제점에 대한 글을 보게 되었다.
우선 공식적으로 정해진 표준이 아니기에 브라우저마다 동작이 다르다(일관성이 없다)는 문제점이 있었고, 또한 React에서 사용할 땐 input과 동작방식이 많은 차이점이 있다는 사실을 알게 되었다 .(아래 링크 참조)
https://www.bucketplace.com/post/2020-09-18-%EC%9B%90%ED%99%9C%ED%95%9C-%EC%BD%98%ED%85%90%EC%B8%A0-%EC%9E%91%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%97%90%EB%94%94%ED%84%B0-%EA%B0%9C%EB%B0%9C%EA%B8%B0/

2. dangerouslySetInnerHTML 사용으로 인한 XSS 공격의 위험성

dangerouslySetInnerHTML 란?
브라우저 DOM에서 innerHTML을 사용하기 위한 REACT의 대체 방법으로 이 태그를 통해 직접적으로 HTML을 삽입 할 수 있다.

XSS란 (Cross Site Script)

XSS 공격은 공격자에 의해 작성된 스크립트가 다른 사용자에게 전달되는 기법이다. 다른 사용자의 웹 브라우저에서 적절한 검증 없이 실행되기 때문에 사용자의 세션을 탈취하거나 , 웹 사이트 변조 또는 악의적인 사이트로 사용자를 이동시킬 수 있다.

    <TextBlock
          key={content.idx}
          contentEditable="true"
          suppressContentEditableWarning
          onInput={handleChange}
          onCompositionStart={handleCompositionStart}
          onCompositionEnd={handleCompositionEnd}
          ref={textRef}
          dangerouslySetInnerHTML={{ __html: content.context }}
          onContextMenu={handleContextMenu}
        />

당시에 위 코드를 통해 HTML 코드가 포함된 context를 그대로 보여주었다.
프로젝트 당시에도 가능하며 사용하지 않는게 좋은 태그인걸 알고 있었지만(이름부터 위험하다..) 프로젝트 마감 일정에 맞추기 위해 사용하였다.

💡방법:

1-1. react-contentEditable 사용하기

  • input과 textarea에서는 bold, italic, color 적용한 결과를 보여줄 수 없기에 div 태그를 수정 할 수있는 contentEditable 속성 사용을 불가피하다는 생각을 하였다.
    (혹시 더 좋은 방법을 알고 계신분은 알려주신다면 감사하겠습니다)
    또한 동작원리를 모르고 라이브러리를 사용하는게 싫어 라이브러리를 잘 사용하지 않았었는데,

react-contenteditable 링크 : https://www.npmjs.com/package/react-contenteditable

태그 커스텀이 필요하였기 때문에
Advenced example 예시 : https://codesandbox.io/s/l91xvkox9l
를 참조하였다.
해당 코드를 참조하면

 <ContentEditable
          className="editable"
          tagName="pre"
          html={this.state.html} // innerHTML of the editable div
          disabled={!this.state.editable} // use true to disable edition
          onChange={this.handleChange} // handle innerHTML change
          onBlur={this.sanitize}
        />

html 속성에서 innerHTML 속성을 사용하는 것을 알 수 있다.
위 예시에서는 XSS에 취약한 innerHTML 속성의 문제점을 해결하기 위해 sanitize-html 라이브러리를 사용하였다.

sanitize 란?

sanitize(소독)은 html의 input 또는 textarea 또는 기타등등의 사용자 입력정보에
와 같은 문자열을 적을시, 웹브라우저에서 문자열이 txt가 아닌 script 기술로 받아들여서 생기는 문제를 방지하는 모듈이다.
사용자가 이를 악용하여 태그들을 삽입해서 악성 스크립트로 변질시켜 실행 시킬 수 있기 때문이다.

HTML Sanitization 할 수 있는 방법은 3가지가 있는데,

  • sanitize-html 라이브러리 사용하기
    https://www.npmjs.com/package/sanitize-html

    Sanitize-html란?

    허용된 태그와 속성 외에 html 태그를 허용하지 않는다. 허용되지 않는 속성이 있다면 지워진다. 기본값으로 하면 디폴트로 허용된 태그들이 존재한다. 허용하는 태그와 허용하지 않는 태그를 따로 지정할 수 있다.

  • HTML Sanitizer API 사용하기
    :https://ui.toast.com/weekly-pick/ko_2021124

  • DOM Purify 라이브러리 사용하기
    https://github.com/cure53/DOMPurify

    DOMPurify란?

    DOM 레벨에서 HTML을 sanitize 해주고 XSS 공격을 막아준다. jsdom 을 사용하면 node 와 같은 서버 레벨에서도 사용 가능하다. DOMPurify는 화이트리스트 접근 방식을 취하는데 특정한 태그와 속성, 프로토콜만 허용한다.

등의 방법이 있었다...

⚽결론

1. react contentEditable 라이브러리 활용

: 라이브러리를 사용하면 모르고 사용하는 느낌이 싫어 프로젝트에서 거의 사용하지 않았었는데,
리팩토링 이전에 contentEditable 속성을 사용하면서 사용했을때의 문제점과 에러를 고치는 과정을 직접 해봤기에 이번엔 라이브러리를 도입하여 사용하기로 하였다.

2. XSS 문제 해결을 위한 HTML Sanitization 할 수 있는 라이브러리 or api 도입

: 마찬가지로 위에 조사한 내용 이외에 작동 원리를 조사하여 프로젝트에 맞는 라이브러리 or api를 도입 할 예정이다.
프로젝트 당시에 XSS 공격 문제 때문에 고민을 많이 했었는데, 그때는 기간 내에 작동하는 프로젝트를 만드는 것이 우선순위여서 특정 태그를 파싱하여 사용하지 못하도록 임시 조취만 취했는데 이번엔 제대로 XSS 문제를 방지 할 수 있을 것이란 기대가 된다!
완성한 후에 테스트 해서 XSS 공격이 방지가 되는지 테스트 해서 포스팅을 작성하는것을 목표로 하고 있다.

😮참고 자료

  1. https://inpa.tistory.com/entry/NODE-%EB%B3%B4%EC%95%88-%F0%9F%93%9A-sanitize-html-%EB%AA%A8%EB%93%88-%EC%82%AC%EC%9A%A9%EB%B2%95
  2. https://velog.io/@pock11/innerHTML-dangerouslySetInnerHTML
profile
알고 싶은게 많은 front-end 개발자 입니다.

0개의 댓글