코드 캠프 27일차) 웹 에디터와 XSS

민겸·2022년 10월 25일
0

코드캠프_FE09

목록 보기
23/28
  1. Web-Editor
  2. Cross-Site-Script (XSS)
  3. Hydration-Issue

1. Web Editor

웹 에디터 라이브러리

  • React Draft Wysiwyg(What You See Is What You Get)
  • React Quill
  • TOAST UI Editor

오늘은 React Quill 을 한 번 가볍게 사용해볼까 한다.

먼저 npm에서 React Quill을 찾아보자.

yarn add react-quill 로 라이브러리를 다운 받고 같이 있는 css파일도 복붙해준다.

설치를 해준 뒤, 그대로 갖다 써보자.

import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";

export default function ReactQuillPage(){
 
	return <ReactQuill />; 
  
}

그런데 document is not defined 에러가 뜬다...

내가 지금 Next.js를 쓰고 있기 때문인 걸까?
얼마전, localStorage 또는 카카오맵api를 사용할 때 Next.js의 서버에서의 pre-rendering 과정에서 window객체를 불러오지 못하는 문제가 생겼던 경험이 떠올랐다.

이번에도 비슷한 문제인 것 같다. pre-rendering 과정에선 브라우저에 있는 windowdocument객체가 없을테니까. 그런데 난 document를 호출한 적이 없는 것 같은데 왜 떴을까...

그건 바로 react-quill 이 document 객체를 불러오기 때문이다.

해결책으로는 이전과 같이 sciprt태그를 적용해도 무방하겠지만, 이번에는 Next.js의 dynamic import를 사용해보자.

React.js의 dynamic import는 페이지 로딩 속도를 빠르게 해준다.

react-hook-form 과 react-quill 결합하기

hook-form의 setValue 를 react-quill 컴포넌트의 onChange와 결합하면 된다. 하지만 이렇게 하면 register를 사용하는 것이 아니기 때문에 {mode: "onChange"} 상태에도 실시간으로 반영이 되지 않는다.

hook-form은 이런 상황을 위한 함수도 존재한다. 바로 trigger이다.
trigger(트리거시킬 key)를 하게 되면 register로 key를 등록해놓지 않아도 key가 등록된 것처럼 인자로 넣은 key 값이 변경될 때 마다 실시간으로 추적하여 트리거된다.

자 여기까지 웹 에디터를 사용하는 법에 대해선 간략하게 알아봤는데, 작성할 때는 이제 사용할 수 있게 되었지만, 작성한 글을 봤을 때 텍스트 에디터로 꾸민 글이 그대로 나올 것인지 확인해야한다.

왜냐하면 웹 에디터로 작성한 내용을 콘솔로 출력해보면 여러 태그들로 감싸여진 형태로 값이 나오기 때문이다. 이걸 작성하고 그대로 올려버리면 태그들은 적용이 되지 않아서 적용된 스타일이 없는 상태로 그대로 나올 것이다.

예를 들면, 작성한 글의 출력 결과가 아래와 같이 나온다.

ad1294dfs번 작성글

작성자: 누구누구
제목 : 솰라솰라

내용 :  <-- (에디터가 적용된 곳)
	<p><h1>중고 시계 팝니다.</h1></p>

이럴 때 html로 인식하게 만들어서 html을 실행시킬 수 있는 방법이 있다.
내용을 보여줄 태그 속성인 dangerouslySetInnerHTML를 사용하는 것이다.

사용법은 다음과 같다.

// 에디터의 결과가 적용될 태그
<div dangerouslySetInnerHTML={
    {__html: 에디터로 작성된 결과를 불러오는 변수}
  }></div>

!! 주의 !!
div 태그나 span 태그를 사용하여 위 속성을 사용할 땐 반드시 빈 태그로 작성해야한다.

이제는 웹 페이지의 내용에 에디터의 효과가 적용된 것을 볼 수 있다.
하지만 속성의 이름을 보면 알 수 있듯이, 이 속성을 사용해서 HTML태그를 실행시키는 것은 매우 위험한 방식이다.

2. Cross-Site-Script (XSS)

만약 에디터 안에 임의로 태그를 작성하면 그대로 실행되기 때문이다.

다행인 건 이런 1차원적인 해킹 시도는 react-quill에서 자체적으로 막아준다. 태그를 작성해도 작성자가 작성한 태그는 문자열로 인식되어 문자열로 나오게 된다.

이렇게 되면 누군가가 고의적으로 script 태그를 집어넣어서 중요한 정보를 탈취할 수 있게 된다. 이런 사이트의 취약점을 노려서 javascript와 html 코드를 악의적으로 브라우저에 심고 사용자 접속 시 악성 코드가 실행되게 하는 것을 XSS(크로스 사이트 스크립트)라고 부른다. XSSSQL injection과 함께 웹 상에서 가장 기초적인 취약점 공격 방법으로 꼽힌다.

CSRF

이외에도, CSRF(Cross-Site Request Forgery)라는 공격 방법이 있는데, 간단하게 말하자면 사이트 간의 요청을 위조하는 것이다. 이 공격 방법은 2008년 옥션의 개인 정보 유출 사건에서 관리가 계정을 탈취하는 데 사용되기도 했다. 공격 난이도가 높은 편이 아니어서 흔히 사용된다.

공격 방법은 해킹할 사이트의 주소 패턴을 분석해 임의로 링크를 만들어 메일로 보내어 사용자가 클릭하면 비밀번호가 해커의 의도대로 초기화되게 한다거나 악성 코드가 담긴 이미지 태그를 XSS기법으로 집어넣어서 코드가 작동하게 만드는 방법도 있다. 대개의 경우 웹 사이트는 이미지 태그를 필터링하지 않기 때문에 가능한 공격이다.

방어

악성 코드를 자동으로 차단해주는 보안 라이브러리를 사용하는 방법과 토큰을 발급하는 방법이 있다.

react-quill의 인풋값 같은 경우 보안 라이브러리 dompurify 의 sanitize로 감싸주면 악성 코드를 감지해 차단해준다.

그리고

비밀번호와 같은 민감한 정보를 처리할 땐 세션에 토큰을 발급해서 해당 토큰이 없는 상태에서 동작들이 이루어지면 요청을 거부하는 방법이 있다.

보안을 생각하며 코드를 짜는 것을 Secure Coding이라고 한다.

OWASP TOP10

Open Web Application Security Project

SQL 인젝션 예)

검증 로직이 다음과 같다는 예시를 들었을 때,

if(id === "user@user.com" && password === "1234"){
	logInSuccess();
}

아이디는 알지만 비밀번호를 모를 때
아무 비멀번호를 입력하고 뒤에 || 1 === 1 을 붙여서 통과한다.

3. Hydration issue

웹 에디터를 사용해봤고 에디터를 통해 작성된 글을 안전하게 웹 페이지에 렌더링하는 것까지 성공했다.

그런데, 에디터가 적용되는 태그에 스타일을 먹이면 전체 페이지의 렌더링이 끝난 후 스타일이 이상하게 바뀌어져 있다.

이것은 서버에서 pre-rendering 할 때와 브라우저에서 그릴 때의 상황이 다르기 때문이다.
서버에서 pre-rendering 할 때는 모든 것을 다 그리지 않고 태그와 CSS 위주로 그린다. 그 후 브라우저에서 다시 그리게 되는데, 모든 것을 다시 그리기엔 비효율적이므로 서버에서 pre-rendering할 때 그렸던 것들을 다시 가져오게 되고 서버에서 그려진 css가 브라우저에 적용되어 색이 달라진다.

React.js는 실제 주소가 없다?
-> 어떤 주소로 접속을 하던 상관없이 모든 페이지의 html, css, js를 다운로드 받고 브라우저에서 가짜 주소를 만들어준다.

Next.js는 build 하게 되면 모든 파일들을 pre-rendering한 파일이 따로 생긴다.

자바스크립트를 적용하는 것이 Hydration!

동시 다운로드 최대 6개까지 가능

왼쪽은 빌드했을 때 생기는 (프리 렌더링을 위한)html 파일이고
오른쪽은 내가 작성한 코드이다.

profile
기술부채상환중...

0개의 댓글