サンドボックスでサードパーティコードを実行する

ウィキペディアの記事が述べているように、サンドボックスはプログラムを安全に実行するためのメカニズムです。 サンドボックスは、多くの場合、テストされていないコード、未知のソースからのテストされていないコードの実行、およびウイルスの実行と検出に使用されます。



ある種のプロジェクトがあり、ユーザーが独自のスクリプト(ウィジェット、アドオン、プラグイン)を作成できるというタスクがあることを想像してください。 カスタムスクリプトには何も問題がないことを望みます(Cookieを盗むことは、できる限り少なくします)。



この記事では、サイバー犯罪者が実行できる攻撃と、サードパーティのコードを安全に実行する方法について説明します。



まず、予防しなければならない種類の攻撃から始めましょう。



攻撃の種類



次に、例(元の記事へのリンク)を含む「攻撃ベクトル」の束があります。視野を広げることに興味がない場合は、投稿の最後までスクロールします。 攻撃はクロスブラウザではありません。



GlobalObjectPoisoning-グローバルオブジェクトの中毒

Array.prototype[4] = 'four'; var a1 = []; alert('a1 has length ' + a1.length + ' but element 4 is ' + a1[4]); var a2 = new Array(5); alert('a2 has length ' + a2.length + ' and its element 4 is also ' + a2[4]);
      
      





EvalArbitraryCodeExecution -evalおよびFunctionコンストラクターはサードパーティコードを実行できます

 eval('alert("your cookie is " + document.cookie)'); (new Function('alert("your cookie is " + document.cookie)'))();
      
      





ArgumentsMaskedByVar -Operaでvar引数として偽装された関数引数の配列

 (function (a, b, c) { var arguments = [1, 1, 1]; alert('arguments[0] === ' + arguments[0] + ', a=' + a); arguments[0] = 2; alert('arguments[0] === ' + arguments[0] + ', a=' + a); })(0, 0, 0);
      
      





CrossScopeParameterModification -arguments配列を使用すると、パラメーターを変更できます

 (function (a) { arguments[0] = 1; alert('a=' + a); })(0);>
      
      





ArgumentsExposesCaller-呼び出し元を使用して外部関数の引数を取得することが可能

 function untrusted() { alert('got function ' + untrusted.caller + ' : ' + arguments.callee.caller.arguments[0]); } (function trusted() { untrusted(); })(4);
      
      





FunctionMemberCrossScopeParameterAccess-内部関数から外部関数の引数を置き換えることができます

 function f(a) { g(); alert(a); } function g() { f.arguments[0] = 1; } f(0)
      
      





TypeofInconsistent - webkitの正規表現に関するtypeofバグ

 'function' === (typeof /./) 'function' === (typeof alert)
      
      





InaccessibleLocalVariables -catch(localVarName)を使用すると、ローカル変数が利用できない場合があります

 (function () { var arguments; alert('arguments === undefined: ' + (arguments === undefined)); })(); (function () { var e; try { throw 1; } catch (e) { } alert('arguments === undefined: ' + (arguments === undefined)); })(); (function () { var e = 1; try { throw 2; } catch (e) { } alert('e === 1 : ' + e); })();
      
      





CatchBlocksScopeBleed -catchを使用してグローバル変数を置き換えることができます

 var a = 0; (function () { try { throw 1; } catch (a) { } })(); alert(a); // alerts 1 on old FF (function () { var a = 0; try { throw 1; } catch (a) { } alert(a); // alerts 1 on IE 6 and 7 (IE 8 not tested) })();
      
      





GlobalScopeViaThis-関数でthisを使用してグローバルスコープにアクセスできます

 (function () { alert('your cookie is ' + this.document.cookie); })(); setTimeout( function () { alert('your cookie is ' + this.document.cookie); }, 0)
      
      





DeleteUnmasksGlobals-を使用して開くことができる非表示のグローバル変数

  with ({ document: null }) { delete document; alert('your cookie is ' + document.cookie); }
      
      





FunctionConstructor-関数コンストラクターは、「constructor」プロパティからアクセスできます

 ((function () {}).constructor)( 'alert("document.cookie = " + document.cookie)')()
      
      





ObjectEvalArbitraryCodeExecution -Object.evalを使用すると、Firefoxで任意のコードを実行できます。

 ({}).eval('alert("Your cookie is " + document.cookie)')
      
      





ObjectWatch-Object.watchを使用すると、外部データを汚染して受信できます

 function untrusted(o) { o.watch( 'private_', function (obj, oldval, newval) { alert('untrusted got oldval ' + oldval + ' and newval ' + newval); return 'poisoned'; // substitute a bogus value }); } // Trusted code var o = { private_: 'old' }; untrusted(o); o.private_ = 'new'; alert('private is now ' + o.private_);
      
      





ObjectToSourceLeaksPrivates -Object.toSourceおよびunevalを使用すると、プライベートプロパティにアクセスできます。

 // Untrusted code function untrusted(o) { // untrusted need not attempt to access private_ directly var privateValue = o.toSource().match(/private_:\s*(\d+)/)[1] * 1; alert('private value is ' + privateValue); } var o = { private_: 4 } untrusted(o);
      
      





FunctionMethodsLeakGlobalScope-Function.callまたはFunction.applyは、この値の一部を使用してグローバルオブジェクトを開くことができます。

 (function () { alert(this === window); }).call(null); (function () { alert(this === window); }).call(undefined); alert(window === ([]).sort.call()); alert(window === ([]).reverse.call()); // Firefox2 only. [https://bugzilla.mozilla.org/show_bug.cgi?id=406337] var o = { valueOf: function () { return null } }; (function () { alert(this === window); }).call(o);
      
      





ConditionalCompilationComments-条件付きコンパイルにより、攻撃者はコードを隠すことができます。

 /*@cc_on @*/ /*@if (1) alert(document.cookie) @end @*/
      
      





StringObfuscationIsEasy-文字列の難読化

 (function () { var s = 'cons'; s += 'tructor'; (new ((function () {})[s])('alert("hello")'))(); })();
      
      





ParentCircumventsScoping-__parent__を使用すると、任意のスコープから変数にアクセスできます

 (function () { var alert = null; // boilerplate that masks global alert (function () { // untrusted code that can't access alert directly ({}).__parent__.alert('hello'); })(); })();
      
      





JsControlFormatChars -RTLまたは[:Cf:] 反転文字を使用して、コメント内のコードを非表示にできます。

 <html> <body onload=" /&#x200D;/.test(''); /* alert('hi'); // */ "> </body> </html>
      
      





InconsistentlyReservedKeywords - Context -Sensitive Words:const constructor prototype

 this['const'] = 0; const alert = f(); // looks like an assignment to self. function f() { return alert; } // looks like a reference to an undefined local. alert('hello world');
      
      





ErrorExposesParameterValues-エラースタックトレースを使用して、外部関数に渡されたパラメーターにアクセスできます

 function skroob(luggageCombination) { darkHelmet(); } function darkHelmet() { var combo = Number((new Error).stack.match(/skroob\((\d+)\)/)[1]); alert('Only an idiot would use that combination!: ' + combo); } skroob(1234);
      
      





RegexpsLeakMatchGlobally-正規表現は、最後の正規表現に送信された最後の行で実行できます

 // Privileged code (function () { var queryString = document.location.search; // Assume it's "?password=1234" function params() { return queryString.split(/[&?]/g); } if (params()[0] === 'debug=on') { // ... } })(); // Unprivileged code without direct access to document.location (function () { alert(/.*/.exec()); })();
      
      





EvalBreaksClosureEncapsulation - evelを呼び出すと、ffの古いバージョンでスコープのカプセル化が壊れる場合があります

 function counter(i) { return function () { return ++i; }; } var myCounter = counter(0); alert(myCounter()); // => 1 eval('i = 4', myCounter); alert(myCounter()); // => 5 on Firefox 2, 2 on other browsers
      
      





PostIncrementAndDecrementCanReturnNonNumber-ポスト - インクリメントとポストデクリメントは数値ではない場合があります-関数コンストラクターを取得する方法

  (function() { var c = 'constructor'; var F = (function(){})[c++]; // Function constructor F('alert("toast")')(); })();
      
      







html、css code.google.com/p/google-caja/wiki/AttackVectorsからの攻撃を含む、 あらゆる攻撃



これらすべての攻撃を考えると、プラグインが自律的に機能しないように、APIを提供する必要があります。



プラグインに提供する必要がある機能



1.一部のユーザーデータにアクセスします。

2.ユーザーに代わっていくつかのアクションを実行します。



攻撃者から自分を隔離し、優れた開発者にすべての可能性を与える方法?!



1.モデレート



画像

コードに精通しているモデレーターのチームを雇うことができ、さらにユーザーからのバグレポートを受け入れます。

欠点:非常に高価で、非常に非効率的です。 優れたモデレーターは多額の費用を支払う必要がありますが、モデレーターとヒューマンファクターよりも熟練したハッカーが常に存在する可能性があります。 ユーザーはエラーを見つけられないかもしれません。プラグインはユーザーに気付かれずにその汚い行為をすることができます。

プラス:いいえ



2. iFrameのサンドボックス



このオプションはjsfiddleで使用されます

1.ユーザースクリプトを左側のドメインに取り出します

2.アラートプロンプト確認の実行を禁止する

3.ユーザーは自分のフレーム内で何でもする権利を持っています

4. postMessageを介してAPIを提供します(非同期)

短所:共通のドメインがある場合、プラグインは他のプラグインを攻撃できます。 非同期交換。 アラートプロンプト確認以外の機能があり、ユーザーに干渉する場合があります。 すべてのブラウザがpostMessageをサポートしているわけではありません

利点:サンドボックスの簡単な実装

詳細: dean.edwards.name/weblog/2006/11/sandbox



3. WebWorkersのサンドボックス



ワーカーは優れたサンドボックスであり、ブラウザー環境によって既に制限されています。

1. postMessageを使用してAPIを提供します(非同期)

2.インターフェイス要素のライブラリを作成する必要があります

3.要素はイベントに非同期的に応答します

欠点:プラグイン開発者はインターフェースコンポーネントに制限されています。 非同期交換およびイベント。 すべてのブラウザがWebWorkersをサポートしているわけではありません。

利点:サンドボックスの簡単な実装

例: github.com/eligrey/jsandbox



4.静的分析とコードへのコード変換



ソースコードを分析し、潜在的に危険なリンクを安全なリンク(css javascript html)に置き換えるか、潜在的に危険なリンクをスキップしません。

短所:出力なし、ソースコードが得られない

プラス:どこでも動作



4.1。 ダグラス・クロックフォードのADsafe


画像

ADsafeは、ゲストコードが重要なアクションを実行できるほど強力なJavaScriptのサブセットを定義し、スクリプトがソースコードを破損または侵入することを防ぎます。

ADsafeは、安全でないか、ブラウザコンポーネントへの制御されていないアクセスを提供する機能をJavaScriptから削除します。 リストには、グローバル変数、this、arguments、eval、with、arguments、callee、caller、constructor、eval、prototype、stack、unwatch、valueOf、watch、_で終わるまたは始まる名前、演算子[]、DateおよびMath .random

制限:コードを実行する前に、JSLintを処理する必要があります。コードはUTF-8である必要があり、html idは一意である必要があります

短所:開発者の過度の制限

プラス:どこでも動作

詳細については、 www.adsafe.orgをご覧 ください。

ここでadsafeで遊ぶことができます: www.jslint.com (ADsafeフラグを有効にします)



4.2。 Google caja


画像

ADsafeとは異なり、Google Cajaは(「cajoler」コンパイラーを使用して)JavaScript、HTML、CSSコードを安全な(cajoled)JavaScript、HTML、CSSコードに変換します。 ajolerは、静的分析を実施して、静的分析が不可能な潜在的に危険な瞬間を特定し、その過程で動的にチェックします。 さらに、cajolerは仮想iframeを使用してDOMチャンクを仮想化します。 Cajaは、 ここで説明するすべてのタイプの攻撃から保護します

短所:変更されたコードを取得します

利点:どこでも動作し、開発者に不必要な制限を課しません

コード翻訳の例





 <script> alert(document.cookie); top.location = "http://www.thinkfu.com/evil.gif"; </script>
      
      







 <script> { ___.loadModule({ 'instantiate': function (___, IMPORTS___) { return ___.prepareModule({ 'instantiate': function (___, IMPORTS___) { var dis___ = IMPORTS___; var moduleResult___, x0___, x1___; moduleResult___ = ___.NO_RESULT; try { { (IMPORTS___.alert_v___ ? IMPORTS___.alert : ___.ri(IMPORTS___, 'alert')).i___((x0___ = IMPORTS___.document_v___ ? IMPORTS___.document : ___.ri(IMPORTS___, 'document'), x0___.cookie_v___ ? x0___.cookie : x0___.v___('cookie'))); moduleResult___ = (x1___ = IMPORTS___.top_v___ ? IMPORTS___.top : ___.ri(IMPORTS___, 'top'), x1___.location_w___ === x1___ ? (x1___.location = 'http://www.thinkfu.com/evil.gif') : x1___.w___('location', 'http://www.thinkfu.com/evil.gif')); } } catch (ex___) { ___.getNewModuleHandler().handleUncaughtException(ex___, IMPORTS___.onerror_v___ ? IMPORTS___.onerror : ___.ri(IMPORTS___, 'onerror'), 'unknown', '2'); } return moduleResult___; }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087717 }).instantiate___(___, IMPORTS___), ___.prepareModule({ 'instantiate': function (___, IMPORTS___) { var dis___ = IMPORTS___; var moduleResult___; moduleResult___ = ___.NO_RESULT; { IMPORTS___.htmlEmitter___.signalLoaded(); } return moduleResult___; }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087733 }).instantiate___(___, IMPORTS___); }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087748 }); } </script>
      
      





スクリプトは「信頼されていないガジェットが言う:未定義」を警告し、リダイレクトしません

ご覧のとおり、ソースコードは入手にはほど遠いですが、エンドユーザーは悪意のある攻撃から保護されています



プロジェクトページ: code.google.com/p/google-caja

ここでGoogle Cajaをツイストできますcaja.appspot.com



使用しているサンドボックス化の方法を聞きたいのですが、実装の例はありますか?



批判、質問、提案を歓迎します!



PSカタを壊したことをおpoびします-パーサーは寝坊しました



All Articles