기본적으로 react에서 {}괄호를 사용하여 데이터를 바인딩하면,
XSS공격으로부터 방어하기 위해 자동적으로 값이 escape됩니다.
이 보안책은 오로지 testcontent
를 렌더링할 때만 일어나며,
여타 다른 HTML attributes를 렌더링시에는 일어나지 않습니다.
Do this:
<div>{data}</div>
Don't do this:
<form action={data}>...
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>
렌더링된 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) }} />
따라서 컨텐츠를 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;
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
);
});
일부 버전의 third-party components들은 보안 이슈가 있습니다.
dependencies를 체크해보고, 더 나은 버전으로 업데이트 할 수 있는지 확인합니다.
free Snyk CLI와 같은 툴을 사용해 취약성을 확인할 수 있습니다.
소스 코드 관리 시스템과 결합하여, 취약성을 자동으로 해결할 수 있습니다.
JSON 데이터를 서버사이드 렌더링 된 react pages와 함께 보내는 것은 일반적인 일입니다.
언제나 "< characters"와 같은 benign 값을 사용하여 injection 공격을 방어할 수 있어야 합니다.
JSON으로부터 HTML에서 사용한 중요한 값을 escape합니다.:
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace( /</g, '\\u003c')}
react는 과거에 심각한 취약성을 가진 버전이 있으므로, 늘 최신 상태로 유지하는 것이 좋습니다.
ESLint와 같은 Linter를 사용하면 자동적으로 보안 이슈를 막아줌과 코드의 교정을 도와줍니다.
ESLint React security config을 사용하여 보안 이슈를 해결할 수 있습니다.
husky와 같은 라이브러리를 사용하여 보안과 관련된 Linter 이슈가 생겼을 때,
commit을 방지하는 pre-commit hook을 작성할 수 있습니다.
종종 라이브러리 코드는 DOM에 HTML을 직접 삽입하는 것과 같은 위험한 행동을 하기위해 사용됩니다.
때문에 Linter를 사용하거나 수동적으로 확인하여
안전하지 않은 react 보안 매커니즘으로부터 방어해야합니다.
dangerouslySetInnerHTML
, innerHTML
, unvalidated URLs 그 외 여타 다른 안전하지 않은 패턴을 사용하는 라이브러리 코드를 되도록이면 사용하지 않도록 합니다.
보안 Linter를 node_modules
폴더에 사용하여 라이브러리 코드를 안전하지 않은 패턴으로부터 방어할 수 있도록 합니다.
번역이 서툴러 의역, 오역이 존재할 수 있습니다. 관련 피드백은 감사히 받겠습니다.