10가지 예제로 알아보는 react 보안

Sol·2020년 12월 22일
6

출처:10 React security best practices
fe-news 12

10 React security best practices

  1. Default XSS Protection with Data Binding
  2. Dangerous URLs
  3. Rendering HTML
  4. Direct DOM Access
  5. Server-side Rendering
  6. Detecting Vulnerabilities in Dependencies
  7. Injecting JSON State
  8. Detecting Vulnerable Versions of React
  9. Configuring Security Linters
  10. Avoiding Dangerous Library Code

1. Default XSS Protection with Data Binding

기본적으로 react에서 {}괄호를 사용하여 데이터를 바인딩하면,
XSS공격으로부터 방어하기 위해 자동적으로 값이 escape됩니다.
이 보안책은 오로지 testcontent를 렌더링할 때만 일어나며,
여타 다른 HTML attributes를 렌더링시에는 일어나지 않습니다.

Do this:

<div>{data}</div>

Don't do this:

<form action={data}>...

2. Dangerous URLs

URL은 javascript: 프로토콜 URL을 통해 동적 스크립트 내용을 담을 수 있습니다.
따라서 보안책으로 들어오는 링크들의 프로토콜이
"http:" 혹은 "https:"인지 확인하고 인증된 값만을 허용하는 기능을 두어 방지할 수 있습니다.

Do this:

function validateURL(url) {
  const parsed = new URL(url)
  return ['https:', 'http:'].includes(parsed.protocol)
}

<a href={validateURL(url) ? url : ''}>Click here!</a>

Don't do this:

<a href={attackerControlled}>Click here!</a>

3. Rendering HTML

렌더링된 DOM노드에 dangerouslySetInnerHTML태그를 사용하여
직접적으로 HTML을 삽입할 수 있습니다.
이러한 링크들은 미리 검사하여 방지할 필요가 있습니다.
dangerouslySetInnerHTML prop에 지정되기 전에 모든 값들을
dompurify와 같은 sanitization library를 사용하여 sanitize해주어야 합니다.

Use dompurify when inserting HTML into the DOM:

import purify from "dompurify";
<div dangerouslySetInnerHTML={{ __html:purify.sanitize(data) }} />

4. Direct DOM Access

따라서 컨텐츠를 DOM nodes의 직접적으로 넣으려 DOM에 접근해서는 안됩니다.
dangerouslySetInnerHTML 태그를 사용할 경우 dompurify를 사용하여
HTML이 삽입되기 전 sanitize해주어야 합니다.

Do this:

import purify from "dompurify";
<div dangerouslySetInnerHTML={{__html:purify.sanitize(data) }} />

refs를 사용하지 마시고, findDomNode()를 사용하여
innerHTML와 유사한 프로퍼티나 메서드를 사용하세요.

Don't do this:

this.myRef.current.innerHTML = attackerControlledValue;

5. Server-side Rendering

ReactDOMServer.renderToString()ReactDOMServer.renderToStaticMarkup()와 같은
서버사이드 렌더링 함수를 사용하면, 자동적으로 contents를 이스케이프하게 됩니다.
hydration을 위해 클라이언트로 string을 보내기 전 렌더링에 연결하면 안됩니다.

XSS를 피하기 위해 sanitize가 되지 않은 데이터를 내보내서는 안됩니다.
renderToStaticMarkup()로 출력해 XSS 공격을 회피할 수 있습니다.:

app.get("/", function (req, res) {
  return res.send(
    ReactDOMServer.renderToStaticMarkup(
      React.createElement("h1", null, "Hello World!")
    ) + otherData
  );
});

6. Detecting Vulnerabilities in Dependencies

일부 버전의 third-party components들은 보안 이슈가 있습니다.
dependencies를 체크해보고, 더 나은 버전으로 업데이트 할 수 있는지 확인합니다.
free Snyk CLI와 같은 툴을 사용해 취약성을 확인할 수 있습니다.
소스 코드 관리 시스템과 결합하여, 취약성을 자동으로 해결할 수 있습니다.

7. Injecting JSON State

JSON 데이터를 서버사이드 렌더링 된 react pages와 함께 보내는 것은 일반적인 일입니다.
언제나 "< characters"와 같은 benign 값을 사용하여 injection 공격을 방어할 수 있어야 합니다.

JSON으로부터 HTML에서 사용한 중요한 값을 escape합니다.:

window.__PRELOADED_STATE__ =   ${JSON.stringify(preloadedState).replace( /</g, '\\u003c')}

8. Detecting Vulnerable Versions of React

react는 과거에 심각한 취약성을 가진 버전이 있으므로, 늘 최신 상태로 유지하는 것이 좋습니다.

9. Configuring Security Linters

ESLint와 같은 Linter를 사용하면 자동적으로 보안 이슈를 막아줌과 코드의 교정을 도와줍니다.
ESLint React security config을 사용하여 보안 이슈를 해결할 수 있습니다.
husky와 같은 라이브러리를 사용하여 보안과 관련된 Linter 이슈가 생겼을 때,
commit을 방지하는 pre-commit hook을 작성할 수 있습니다.

10. Avoiding Dangerous Library Code

종종 라이브러리 코드는 DOM에 HTML을 직접 삽입하는 것과 같은 위험한 행동을 하기위해 사용됩니다.
때문에 Linter를 사용하거나 수동적으로 확인하여
안전하지 않은 react 보안 매커니즘으로부터 방어해야합니다.

dangerouslySetInnerHTML, innerHTML, unvalidated URLs 그 외 여타 다른 안전하지 않은 패턴을 사용하는 라이브러리 코드를 되도록이면 사용하지 않도록 합니다.
보안 Linter를 node_modules 폴더에 사용하여 라이브러리 코드를 안전하지 않은 패턴으로부터 방어할 수 있도록 합니다.

번역이 서툴러 의역, 오역이 존재할 수 있습니다. 관련 피드백은 감사히 받겠습니다.

profile
야호

0개의 댓글