Symbol - TECH-SHARING-STUDY/FE_STUDY GitHub Wiki
ES6์ ์ถ๊ฐ๋ ์ฌ๋ณผํ์ ์ ๋ํด ์์๋ด ์๋ค.
Symbol์ ์๋ฐ์คํฌ๋ฆฝํธ์ ์์(Primitive)ํ์ ์ผ๋ก ES6์์ ์๋กญ๊ฒ ์ถ๊ฐ๋์์ต๋๋ค.
์์ํ์ ์ ๊ฐ์ฒด๋ ์๋๊ณ ๋ฉ์๋๋ ์๋ ํ์ ์ ์๋ฏธํฉ๋๋ค.
์ฐธ๊ณ ) ๊ธฐ๋ณธ ์๋ฃํ (Primitive) ์ธ ์ฌ์ฏ๊ฐ์ง ๋ฐ์ดํฐ ํ์
- Boolean
- Null
- Undefined
- Number
- String
- Symbol (ECMAScript 6 ์ ์ถ๊ฐ๋จ)
Symbol์ **๊ฐ์ฒด ์์ฑ(object property)**์ ๋ง๋ค ์ ์๋ ์์ ํ์ ์ ๋๋ค.
Symbol ํ์ ์ ์ฃผ๋ก ๊ฐ์ฒด์ ๊ณ ์ ํ ํ๋กํผํฐ์ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ ๋ชฉ์ ์ผ๋ก ์ฐ์ ๋๋ค.
๋ค์ ์์๋ฅผ ๋ณผ๊น์??
var symbolProperty = Symbol("key"); // Symbol(key)
var ob = {};
ob[symbolProperty] = "value";
console.log(ob); // {Symbol(key): "value"}
console.log(ob[symbolProperty]); // "value"
console.log(typeof symbolProperty); // "symbol"
์ด ๋ Symbol์ ์์ฑํ ๋๋ง๋ค ๋ ๋ฆฝ์ ์ธ ๊ฐ์ด ๋๊ธฐ๋๋ฌธ์, ๊ฐ์ string ์ผ๋ก ์ ์ํด๋ ๊ฐ์ ๊ฐ์ด ์๋๋๋ค.
var symbolProperty1 = Symbol("key"); // Symbol(key)
var symbolProperty2 = Symbol("key"); // Symbol(key)
var ob = {};
ob[symbolProperty1] = "value1";
ob[symbolProperty2] = "value2";
console.log(ob); // {Symbol(key): "value1", Symbol(key): "value2"}
console.log(symbolProperty1 === symbolProperty2); // false
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด symbolProperty1, symbolProperty2 ๋ ๊ฐ์ 'key'๋ก Symbol์ ์์ฑํ์ง๋ง ์๋ก ๋ค๋ฆ์ ์ ์ ์์ต๋๋ค.
๋ํ Symbol์ ์์ฑํ์ ๋ value (value of) ๋ ์์ํ ๊ฐ์ด ์๋๋๋ค. ๋ฐ๋ผ์ toString() ๋ฑ์ผ๋ก ๋ฌธ์๋ฑ๊ณผ ํฉ์น ์ ์์ต๋๋ค.
"text" + Symbol("string"); // Error
// Uncaught SyntaxError: Invalid or unexpected token
Symbol์ ๋ค์๊ณผ ๊ฐ์ ์ธ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค.
Symbol();
Symbol.for(); // Symbol๊ณผ ๋ฌ๋ฆฌ ์ ์ญ์ผ๋ก ์กด์ฌํ๋ global symbol table ์ฐธ์กฐ
Symbol.iterator; // iterator ๊ฐ์ฒด๋ฅผ ์ ์ํ๊ธฐ ์ํด ์ฐ์ธ๋ค.
obj[Symbol.iterator] = function* {}
Symbol.for๋ฅผ ๋ ์์ธํ ์์๋ณผ๊น์?
var ob = {};
var a = Symbol.for("key");
var b = Symbol.for("key");
ob[a] = 20;
console.log(ob[b] === 20);
์ด๋ ๊ฒ Symbol.for ๋ก ์์ฑํ Symbol์ ๊ฐ์ 'key'๋ก ๋ง๋ Symbol๊ณผ ๊ฐ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
Symbol ์์ฑ์ ์ด๊ฑฐํ ์์ฑ์ด ์๋๊ธฐ ๋๋ฌธ์ for of ์ด๋ Object.keys ๋ ์ฐพ์ ์ ์์ต๋๋ค.
Symbol ์์ฑ์ ์ฐพ์ ๋๋ Object.getOwnPropertySymbols ๋ก ์ฐพ์์ผ ํฉ๋๋ค.
๋ํ JSON.stringify() ์์๋ ๋ฌด์๋ฉ๋๋ค.
var ob = {
[Symbol("a")]: 10,
[Symbol("b")]: 20,
};
Object.getOwnPropertySymbols(ob);
// [Symbol(a), Symbol(b)]
Object.keys(ob);
// []
for (var i in ob) {
console.log(i);
}
// ๋ฐํ๊ฐ ์์
JSON.stringify(ob);
// "{}"
JSX ๋ฌธ๋ฒ์ผ๋ก ํ๊ทธ๋ฅผ ์์ฑํ ๋ ์ค์ ๋ก๋ ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค.
<marquee bgcolor="#ffa7c4">hi</marquee>;
React.createElement(
/* type */ "marquee",
/* props */ { bgcolor: "#ffa7c4" },
/* children */ "hi"
);
๊ทธ๋ฆฌ๊ณ ์ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
{
type: 'marquee',
props: {
bgcolor: '#ffa7c4',
children: 'hi',
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element'), // ๐ง ์? ์ด๊ฑด ๋ญ์ง?
}
typeof๋ ๋์ฒด ๋ฌด์์ด๋ฉฐ, ์ Symbol()์ ๊ฐ์ผ๋ก ๊ฐ์ง๊ณ ์๋ ๊ฑธ๊น์?
์ผ๋ฐ์ ์ผ๋ก ์์ฑํ๊ณ DOM์ ์ฃผ์ ํ๊ธฐ ์ํด ์ฃผ๋ก ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ณค ํฉ๋๋ค.
const messageEl = document.getElementById("message");
messageEl.innerHTML = "<p>" + message.text + "</p>";
๋ค๋ง message.text๊ฐ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ ๊ณจ์น์ํ์ง๋๋ค.
<img src onerror="stealYourPassword()" />
์ด ๋๋ฌธ์ React ๊ฐ์ ๋ชจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฌธ์์ด ํ ์คํธ์ ๋ํ ์ด์ค์ผ์ดํ์ด ๊ธฐ๋ณธ์ผ๋ก ์ง์๋ฉ๋๋ค.
๋ง์ฝ message.text์ HTML ํ๊ทธ๋ ์ฌํ ๋ค๋ฅธ ์์ํ ํ๊ทธ ๋ฌธ์์ด์ด ๋ค์ด์ค๋ฉด, React๋ ์ด๋ฅผ ์ค์ HTML ํ๊ทธ๋ก ๋ณํํ์ง ์์ต๋๋ค.
React๋ ๋จผ์ ์ ๋ ฅ๊ฐ์ ์ด์ค์ผ์ดํํ ๋ค DOM์ ์ฃผ์ ์ํจ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก HTML ํ๊ทธ๊ฐ ๋์ค๋ ๋์ ๋จ์ํ ๋งํฌ์ ์ฝ๋๋ง ํ์๋๋ค.
๋ง์ฝ HTML์ React element ์์ ๋ฃ์ด์ผํ๋ ์ํฉ์ด๋ผ๋ฉด,
dangerouslySetInnerHTML={{ __html: message.text }}
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์๋์ ์ผ๋ก injection์ ์ผ๋ํด๋๊ณ ๋ง๋ ๊ฒ์ด ๋๊ปด์ง์ฃ ?
๊ทธ๋ฌ๋ ์ด๋ฌํ ์ด์ค์ผ์ดํ ๋ฐฉ๋ฒ์ ์์ ํ ์์ ํ์ง ์์ต๋๋ค. ๋๋ถ๋ถ์ ๊ณต๊ฒฉ์ ์์ฑ(attributes)์ ํตํด ์ด๋ฃจ์ด์ง๋๋ค.
๋ง์ฝ ์๋ฒ์์ ๋ฐ์ message.text์ ์ ๋ณด๊ฐ JSON์ธ ๊ฒฝ์ฐ ์ด๋ป๊ฒํ ๊น์??
๋ง์ฝ ๋น์ ์ ์๋ฒ์ ๊ตฌ๋ฉ์ด ์๊ฒจ, (์๋๋ ๋ฌธ์์ด๋ก ์ ๋ ฅ์ ๋ฐ์์ผ ํ๋๋ฐ) ์ ์ ๊ฐ ์์์ JSON ๊ฐ์ฒด๋ฅผ ์๋ฒ์ ์ ์ฅํ ์ ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๊ณ ํ์. ํด๋ผ์ด์ธํธ ์ชฝ ์ฝ๋์์ ๋น์ฐํ ํด๋น ์ ๋ณด๋ฅผ ๋ฌธ์์ด๋ก ๋ฐ๊ฒ๋ ์ค๊ณ๋์ด ์์ํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค
// ์๋ฒ์ ๊ตฌ๋ฉ์ด ์๊ฒจ JSON์ด ์ ์ฅ๋์๋ค๊ณ ๊ฐ์ ํ์.
let expectedTextButGotJSON = {
type: "div",
props: {
dangerouslySetInnerHTML: {
__html: "/* put your exploit here */",
},
},
// ...
};
let message = { text: expectedTextButGotJSON };
// React 0.13์์ ์ด๋ ์ํํ ์ ์๋ค.
<p>{message.text}</p>;
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด '๋ชจ๋ React element์ Symbol ํ๊ทธ'๋ฅผ ๋ฌ์์ต๋๋ค.
๋ค์ํ๋ฒ React.createElement์ ๋ฐํ๋๋ ๊ฐ์ฒด๋ฅผ ์ดํด๋ณผ๊น์?
{
type: 'marquee',
props: {
bgcolor: '#ffa7c4',
children: 'hi',
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element'),
}
Symbol์ ์ฑ์ง ์ JSON์๋ Symbol๋ฅผ ๋ฃ์ ์ ์์ต๋๋ค.
์ฆ, ์ค์ฌ ์๋ฒ์ ๋ณด์ ๊ตฌ๋ฉ์ด ์๊ฒจ ํ ์คํธ ๋์ JSON์ ๋ฐํํ๋ค ํ๋๋ผ๋, ๊ทธ JSON์๋ Symbol.for('react.element') ์ฝ๋๋ฅผ ํฌํจ์ํฌ ์ ์์ต๋๋ค.
React๋ element.$$typeof ๋ฅผ ์ฒดํฌํ์ฌ, ํด๋น ํค๊ฐ ์๊ฑฐ๋ ๋ฌดํจํ๋ฉด React element ์์ฑ์ ๊ฑฐ๋ถํฉ๋๋ค.
์ฆ Symbol๋ก ์์ฑ๋ ํด๋น ํค๊ฐ ์๋ ๊ฒฝ์ฐ์๋ React element ๋ก ์์ฑ๋์ง ์๋๊ฒ์ด์ฃ
(injection ๋ฑ์ผ๋ก ํด์ปค์ ๊ณต๊ฒฉ์ ์ํ Element์ ์์ฑ์ ๋ฐฉ์งํฉ๋๋ค)
๊ทธ๋ผ Symbol์ ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ๋ค์ ์ด๋จ๊น์?
์์ฝ๊ฒ๋ ์ด๋ค์ ๋ฐฉ๊ธ ์์์ ์ธ๊ธํ ํํ์ ๋ฐ์ ์ ์์ต๋๋ค.
์ผ๊ด์ฑ์ ์ํด element์๋ ์ธ์ ๋ $$typeof ํ๋๊ฐ ํฌํจ๋์ด ์์ผ๋, Symbol๋ฅผ ์ง์ํ์ง ์๋ ํ๊ฒฝ์์ $$typeof ๊ฐ์ Symbol ๋์ number๊ฐ ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค.
0xeac7; // ์ ๋ณด๋ฉด โReactโ์ฒ๋ผ ๋ณด์ด๋๊น์