Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ユーザーが作成したコードをブラウザ上で安全に実行できる Plugin システムへのアプローチ

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Saji Saji
January 08, 2026
470

ユーザーが作成したコードをブラウザ上で安全に実行できる Plugin システムへのアプローチ

Avatar for Saji

Saji

January 08, 2026
Tweet

More Decks by Saji

Transcript

  1. ͜ͷτʔΫͰͷʮ1MVHJOγεςϜʯ ༷ʑͳʮ1MVHJOγεςϜʯ͕ଘࡏ͢Δ͕ɺ͜ͷτʔΫͰ͸ҎԼΛର৅ͱ͢Δ w ϒϥ΢β্Ͱಈ͘΋ͷ 㱠αʔόʔαΠυ  w ඞવతʹ΄΅+4Ͱॻ͔ΕΔ 8BTNͳΒʁΈ͍ͨͳ࿩͸ޙड़ 

    w SE1BSUZ Ϣʔβʔɾύʔτφʔاۀ༷ ʹΑΔ΋ͷ͕΄ͱΜͲ w ۀ຿ɾχʔζʹ߹Θ֦ͤͨுɾޮ཰Խखஈͱͯ͠ར༻͞ΕΔ ͳͷͰ͜ͷൃදͷλΠτϧ͸ʮϢʔβʔ͕࡞੒ͨ͠ίʔυΛϒϥ΢β্Ͱ҆શ ʹ࣮ߦͰ͖Δ1MVHJOγεςϜ΁ͷΞϓϩʔνʯ
  2. +4&OHJOFPO8BTNͰִ཭͢Δ ϝϦοτ👍 w ϝϞϦϨϕϧͰִ཭͞Εͨ+4ͷ࣮ߦ؀ڥ͕ಘΒΕΔ 8BTNͷڧΈ  w ͏·͘ڮ౉͠Λ͢Ε͹ಉظతͳ"1*Λ࡞Δ͜ͱ΋Մೳ σϝϦοτ👎 w

    ΞϓϦέʔγϣϯຊମͱͷڮ౉͠Λࣗ෼ͨͪͰ࣮૷͢Δඞཁ͕͋Δ w ར༻Ͱ͖Δ+4ͷػೳ͸+4&OHJOF࣍ୈ+4ͷݴޠػೳ͔͠࢖͑ͳ͍ w 6*͸ͳ͍ͷͰ%0.͸ૢ࡞Ͱ͖ͳ͍ॳظϩʔυͷ໘Ͱෆར
  3. 3FBMNT4IJNͰִ཭͢Δલఏ ͦ΋ͦ΋3FBMNT &$."4DSJQU3FBMNT ͱ͸ w &$."4DSJQU +4ͷ࢓༷ Ͱఆٛ͞Ε͍ͯΔ֓೦ͷͭ w +4͕ධՁ͞ΕΔάϩʔόϧม਺΍ϏϧυΠϯΫϥεɺ࣮ߦ͞ΕΔίʔυ΍ঢ়

    ଶɾϦιʔεͳͲΛ͢΂ͯ·ͱΊ΋ͷ w ΑΓৄ͘͠͸.%/ͷʮ+BWB4DSJQUFYFDVUJPONPEFMʯͱ͍͏هࣄ͕ྑ͍ 3FBMN4IJNT3FBMNTͱݺ͹ΕΔ࢓૊Έ ֓೦ Λ࣮ݱ͢ΔTIJN w 㲈Ծ૝తʹ3FBMNΛ৽͘͠࡞ΕͯΔΑ͏ʹ͢Δٕज़
  4. બ͹Εͨͷ͸ʮJGSBNFʯͰͨ͠ େ͖͔ͬͨϝϦοτ w 6*Λ͍࣋ͬͯͯ%0.ૢ࡞ΛؚΊͨ΄΅׬ᘳͳ+4࣮ߦ؀ڥͰ͋Δ͜ͱ w ͪΌΜͱઃఆ ޙड़ ͢Ε͹࣮ߦΛ҆શʹִ཭͢Δ͜ͱ͕Մೳ w 8FCͷඪ४ػೳʹ৐ΕΔͷͰϓϥάΠϯػߏ͕ෳࡶԽ͠ʹ͍͘

    ͋Δఔ౓ڐ༰Ͱ͖Δͱ൑அͨ͠σϝϦοτ w ύϑΥʔϚϯεˠ4&0΍ϢʔβମݧΛؾʹ͢Δ΋ͷΑΓ͸एׯ༏ઌ౓͕௿͍ w "1*͕ඇಉظͳΔˠࠓޙ௥Ճ͍ͯ͘͠"1*Ͱॱ࣍ඇಉظͷ΋ͷ͚ͩʹ
  5. JGSBNF ↔︎ ΞϓϦέʔγϣϯຊମͷ௨৴ ΞϓϦέʔγϣϯຊମͱͷ௨৴͸$IBOOFM.FTTBHJOH"1*Λར༻͢Δ $IBOOFM.FTTBHJOH"1*ͱ͸ w ҟͳΔίϯςΩετؒͰ௨৴Λߦ͏ͨΊͷඪ४ػೳ w *GSBNF ↔︎

    ຒΊࠐΈݩϖʔδͭͷJ'SBNFಉ࢜จॻͱ4IBSFE8PSLFS ΞϓϦέʔγϣϯຊମͱ$PSTT0SJHJOJGSBNFͱͰ௨৴͢Δ།Ұͷํ๏ w ٯʹݴ͑͹$IBOOFM.FTTBHJOH"1*ʹݶఆͰ͖Δ
  6. $IBOOFM.FTTBHJOH"1*Ͱͷૄ௨ ຊମˠQMVHJOJGSBNFʹ66*%Λૹ৴͢Δ const uuid = generateUUID(); const channel = new

    MessageChannel(); function onLoad() { // send UUID iframe.contentWindow.postMessage(uuid, "*", [channel.port2]); }
  7. $IBOOFM.FTTBHJOH"1*Ͱͷૄ௨ JGSBNF͸ड͚औͬͨΒૹΓओͷPSJHJOΛνΣοΫͦ͠ͷ··ฦ৴ const handler = (e) => { if (!checkMessageOrigin(e.origin))

    { reject(new Error("Invalid origin")); } messagePort.postMessage(e.data); window.removeEventListener("message", handler); // ... }; window.addEventListener("message", handler);
  8. $IBOOFM.FTTBHJOH"1*Ͱͷૄ௨ ຊମ͸1MVHJOJGSBNF͔Βͷฦ৴Λ֬ೝ 66*%͕ಉ͡PSJHJO͕ਖ਼͍͔͠ const handler = (e) => { if

    (e.data === uuid && checkMessageOrigin(e.origin)) { resolve(channel.port1); } else { reject(new Error("Invalid message origin or uuid")); } channel.port1.removeEventListener("message", handler); }; channel.port1.addEventListener("message", handler);
  9. 4IBEPX3FBMNT1SPQPTBM 3FBMNTΛ໌ࣔతʹ࡞੒Ͱ͖Δ4IBEPX3FBMNΫϥεΛ௥Ճ͢Δ w ࡞੒͞Εͨ3FBMN಺Ͱ͸+BWB4DSJQUΛධՁͰ͖Δ const realm = new ShadowRealm(); const

    result = realm.evaluate(` function add(s1, s2) {return s1 + s2;} add("Hello, ", "world!"); `); console.log(result); // Hello, World!