🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

1073閲覧

ブラウザ上にセキュリティ上の懸念がない任意のスクリプト実行環境を用意したい

payoppa

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

3クリップ

投稿2021/02/10 04:28

編集2021/02/10 07:51

前提・実現したいこと

チャットのようなインタラクティブなWebアプリケーションを構築しようとしています。
そこに、ユーザーがブラウザ上に入力したコードをそのまま実行できる機能の追加を検討しています。
不特定多数に公開することを想定しており、ユーザーtoユーザーで任意コードを送れてしまうので、単純にJavaScriptでeval()するみたいな実装にしたくありません。
また、パフォーマンスの都合上、サーバーにPOSTして実行するのは避けたいなと考えています。
実現するライブラリや方法をご存知の方はいらっしゃらないでしょうか?

例えば、以下のようなものがあればいいなと思っていました。

  • ブラウザ上で実行できるスクリプト実行エンジン。
  • JavaScriptで window.location などの任意のAPI使用を制限する方法。

利用イメージ

ユーザー入力のコードは、例えば以下のようなものを想定しています。

js

1function onPostRound(ctx, api) [ 2 if (ctx.round === 2) { 3 api.triggerEvent('hitman', {}); 4 } 5} 6 7function hitman(arg, api) { 8 // ... 9}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

plasticgrammer

2021/02/10 05:51

どこまでできると要件が満足できるのか知りたいのですが、 DOM要素を操作することは不可としてよいのでしょうか? DOM要素の操作は不可とした場合、それ以外で何をしたいのでしょうか。(提示頂いた利用イメージでは、理解が進みませんでしたので補足をお願いしたいです)
payoppa

2021/02/10 07:23

一番理想的なのは、DOM操作含むブラウザが提供するWindow配下のAPIが使えなくなることです。 要求としては、以下2点を満たす処理系が欲しいです。 ・パラメータ付きで処理が起動できること。 ・結果を何らかの形で呼び出し元(JavaScript)で返却できること。API経由でも何らかのストリーム経由でもよし。 目的はセキュリティとしていますが、実のところ個人でやるものなので、ある程度コントロールできれば満足です。(最悪、アプリで注意喚起を強く入れて自己責任とすることを考えています。) 仮に被害を想定するなら、例えば悪意のある人物が、同セッションに居合わせたユーザーにJavaScriptに埋め込まれた任意のバイナリをダウンロードさせて実行を促すとか、認証と称したUIを表示してID/パスワードを詐取するとかを防げたらな、という感じです。
guest

回答1

0

ベストアンサー

きちんと試してはいませんが、<iframe sandbox="allow-scripts">上で実行するのはどうでしょうか。

html

1 <iframe id="test" sandbox="allow-scripts" src=""></iframe> 2 <script src="main.js"></script>

js

1document.getElementById('test').src = URL.createObjectURL(new Blob([` 2<h1>test</h1> 3<script> 4 console.log('test'); 5 // 動作する 6 7 console.log(parent.location); 8 // 取得できる 9 10 // console.log(parent.document); 11 // エラー 12 13 // console.log(parent.location.href); 14 // エラー 15 16 console.log(document.referrer); 17 // "" 18 19 fetch("/"); 20 // リクエストヘッダーの origin が null になる → CORSでブロックできる 21 22 alert('"alert" not working'); 23 // エラーにならないが動作しない 24 25 // console.log(document.cookie); 26 // エラー 27</script> 28`], { type: 'text/html' }));

参考:
CSP: sandbox - HTTP | MDN

投稿2021/02/10 05:44

編集2021/02/10 05:53
Lhankor_Mhy

総合スコア36928

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

payoppa

2021/02/10 09:42

ありがとうございます、お恥ずかしながら、Contents Security Policyという機能を初めて知りました。 すごくサンドボックスしてて信頼感しかないですね! ただ試した所、iframe内の処理結果をiframeの外から取り出す方法が分からず苦戦しています。 sandboxにallow-same-originを付与するのは本末転倒だし、 パイプになりそうだったlocalStorageもallow-same-originが必要。 なんとかsandbox属性にあたるプロパティを動的に変更できないか探すも、それらしきものになかなかありつけず。 引き続き、研究になりそうです。
payoppa

2021/02/10 11:31 編集

ありがとうございます。手元でそれらしく動作するコードができました!! 迅速で正確な回答、恐れ入ります。 `````````````````````````````````````````````````````` // sandbox環境にスクリプトを仕込む document.getElementById('test').src = URL.createObjectURL(new Blob([` <h1>test</h1> <script> // sandbox環境に提供するAPIなどの想定 const scriptid = 'usr0001'; const api = { requestCommands: (commands) => { parent.postMessage( { type: 'requsetCommand', sender: 'userscript:' + scriptid, commans: commands }, '*' ); } }; // 親からPostMessageを受けた時のイベントハンドラ window.addEventListener('message', (event) => { const data = event.data || {}; switch (data.type) { case 'postRound': !window.onPostRound || onPostRound(event.data); break; } }); // 以下、ユーザー実装する想定のコード // イベントハンドラ function onPostRound(ctx) { if (ctx.round === 2) { hitman({damage: 1}); } } // サブルーチン function hitman(arg) { console.log('hitman(' + JSON.stringify(arg) + ')'); api.requestCommands([ {command: 'damage', target: 'p1', amount: arg.damage} ]); } </script> `], { type: 'text/html' })); // sandbox→親に渡ってくるメッセージのイベントハンドラ window.addEventListener('message', (event) => { console.log('parent reserved message:', event); }); // 親→sandboxにイベント発火。 document.getElementById('test').onload(() => { document.getElementById('test').contentWindow.postMessage({type: 'postRound', round: 2 }, '*'); }); ``````````````````````````````````````````````````````
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問