Symbol - TECH-SHARING-STUDY/FE_STUDY GitHub Wiki

Javascript Symbol (์‹ฌ๋ณผ) - ์กฐ์ฐฌ๊ธฐ

ES6์— ์ถ”๊ฐ€๋œ ์‹ฌ๋ณผํƒ€์ž…์— ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

Symbol์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์›์‹œ(Primitive)ํƒ€์ž…์œผ๋กœ ES6์—์„œ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์›์‹œํƒ€์ž…์€ ๊ฐ์ฒด๋„ ์•„๋‹ˆ๊ณ  ๋ฉ”์„œ๋“œ๋„ ์•„๋‹Œ ํƒ€์ž…์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ) ๊ธฐ๋ณธ ์ž๋ฃŒํ˜• (Primitive) ์ธ ์—ฌ์„ฏ๊ฐ€์ง€ ๋ฐ์ดํ„ฐ ํƒ€์ž…

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol (ECMAScript 6 ์— ์ถ”๊ฐ€๋จ)

Symbol์˜ ํŠน์ง•

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();
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์˜ privateํ•œ ์„ฑ์งˆ

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);
// "{}"

React ์™€ Symbol

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()์„ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ์š”?

HTML injection

์ผ๋ฐ˜์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  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์˜ ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค)

๋ฒˆ์™ธ - ES6 Symbol์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋Š”์š”

๊ทธ๋Ÿผ Symbol์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋“ค์€ ์–ด๋–จ๊นŒ์š”?

์•„์‰ฝ๊ฒŒ๋„ ์ด๋“ค์€ ๋ฐฉ๊ธˆ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ํ˜œํƒ์„ ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ผ๊ด€์„ฑ์„ ์œ„ํ•ด element์—๋Š” ์–ธ์ œ๋‚˜ $$typeof ํ•„๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋‚˜, Symbol๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํ™˜๊ฒฝ์—์„  $$typeof ๊ฐ’์— Symbol ๋Œ€์‹  number๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

0xeac7; // ์ž˜ ๋ณด๋ฉด โ€œReactโ€์ฒ˜๋Ÿผ ๋ณด์ด๋‹ˆ๊นŒ์š”

์ฐธ๊ณ  ์ž๋ฃŒ

Javascript์™€ Symbol Symbol

์™œ-React-Element์—๋Š”-typeof-ํ”„๋กœํผํ‹ฐ๊ฐ€-์žˆ์„๊นŒ

โš ๏ธ **GitHub.com Fallback** โš ๏ธ