web-dev-qa-db-ja.com

(ブラウザで)JavaScriptをハックするのはどれほど簡単ですか?

私の質問はJavaScriptのセキュリティに関係しています。

Backbone または AngularJS のようなJavaScriptフレームワークを使用していて、安全なエンドポイントが必要な認証システムを想像してみてください。サーバーには常に最後のWordがあり、あなたが望むことをする権限があるかどうかをチェックするので、それは問題ではありません。

しかし、サーバーを使用せずに少しセキュリティが必要な場合はどうでしょうか。それは可能ですか?

たとえば、クライアント側のルーティングシステムがあり、ログインしているユーザーに対して具体的なルートを保護したいとします。したがって、保護されたルートへのアクセスが許可されているかどうかを尋ねてサーバーにpingし、続行します。問題は、サーバーにpingすると、応答を変数に格納するため、次にプライベートルートにアクセスしたときに、既にログインしているかどうか(サーバーにpingしない)が確認され、応答に行くかどうか。

ユーザーがその変数を変更してアクセスするのはどのくらい簡単ですか?

私のセキュリティ(およびJavaScript)の知識はあまりよくありません。しかし、変数がグローバルスコープになく、getterのみがあり、setterはないモジュールパターンのプライベート部分にある場合、その場合でも、ハックできますか?

37
Jesus Rodriguez

これを読む前に ヨアヒムの答え を読んでください。彼はクライアント側の脆弱性の背後にある一般的な理由をカバーしています。さて、この問題をどうやって回避するかについての提案について...

リクエストごとにサーバーで手動で認証する必要のないクライアント/サーバー通信用の安全なスキーム:

あなたはstillサーバーに最後の発言権を与え、サーバーstillはクライアントのすべてを検証する必要があります言いますが、それは透過的に起こります。

[〜#〜] https [〜#〜] プロトコルを想定して、 中間者攻撃 (MITMA)を防止します。

  • クライアントは初めてサーバーとハンドシェイクし、サーバーはクライアントの公開キー/を生成し、非対称暗号化スキームを使用してプライベートキーを保持します。クライアントは、サーバーの「公開」鍵をローカルストレージに保存し、どこにも保存しない安全なパスワードで暗号化します。

  • クライアントは現在オフラインです。クライアントは信頼できるアクションを実行したいと考えています。クライアントは自分のパスワードを入力し、サーバーの公開鍵を取得します。

  • クライアントはそのデータの知識に基づいてアクションを実行し、クライアントはサーバーの公開キーを使用して、実行するすべてのアクションを暗号化します

  • クライアントがオンラインの場合、クライアントはクライアントIDを送信し、クライアントが実行したすべてのアクションはサーバーの公開鍵で暗号化されたサーバーに送信されます。

  • サーバーはアクションを復号化し、それらが正しい形式であれば、クライアントで発生したものであると信頼します。

注:

  • クライアントのパスワードはどこにも保存できません。保存しないと、攻撃者がキーを取得し、アクションに独自の署名を付ける可能性があります。このスキームのセキュリティは、サーバーがクライアントに対して生成するキーの整合性にのみ依存しています。そのキーを要求するとき、クライアントはサーバーで認証される必要があります。

  • 実際には、セキュリティのためにserverを信頼し、notクライアントを信頼しています。クライアントが実行するすべてのアクションmustサーバー上で検証します。

  • web worker で外部スクリプトを実行することが可能です。覚えておいてくださいevery[〜#〜] jsonp [〜#〜] 現在のリクエストは、はるかに大きなセキュリティ問題です。すべてのコストでキーを保護する必要があります。それを失うと、攻撃者はユーザーになりすますことができます。

  • これは、「サーバーへのpingを実行しない」という要求に応えます。攻撃者は、鍵を知らなければ、偽造データを含むHTTPリクエストを単純に模倣することはできません。

  • ヨアヒムの答えはまだ正しいです。実際には、すべての認証サーバー上を実行しています。ここで保存した唯一のことは、毎回サーバーでのパスワード検証の必要性です。これで、コミットしたり、更新されたデータをプルしたりするときにサーバーを関与させるだけで済みます。ここで行ったのは、クライアント側で信頼できるキーを保存し、クライアントに再検証してもらうことだけです。

  • これは、(たとえば、AngularJSを使用した)単一ページアプリケーションのかなり一般的なスキームです。

  • [〜#〜] rsa [〜#〜] のようなスキームではそれが何を意味するのか、サーバーの公開鍵を「public」と呼んでいますが、これは実際にはスキーム内の機密情報であり、保護する必要があります。

  • パスワードをメモリのどこにも保存しません。ユーザーにオフラインコードの実行を開始するたびに、ユーザーに「オフライン」パスワードを送信させます。

  • 独自の暗号化を導入しない-認証にはスタンフォード大学のような既知のライブラリを使用します。

  • このアドバイスを参考にしてください現状のまま。この種の認証を実際のビジネスクリティカルなアプリケーションに導入する前にセキュリティの専門家に相談してください。これは、painfulであり、間違えやすい重大な問題です。

他のスクリプトがページにアクセスできないのはcriticalです。これは、Webワーカーでのみ外部スクリプトを許可することを意味します。ユーザーがパスワードを入力したときにパスワードを傍受する可能性がある他の外部スクリプトを信頼することはできません。

Promptnotを完全に確信がなく、実行を延期しない場合は、インラインパスワードフィールドを使用してください(つまり、イベントがイベントにアクセスできるようになるが、同期コードでのみ存在する)。また、実際にはパスワードを変数に格納しないでください。これも、ユーザーのコンピューターが危険にさらされていないことが信頼できる場合にのみ機能します(サーバーに対して検証する場合も同様です)。

もう一度付け加えたいと思いますまだクライアントを信頼していません。あなたできないクライアントだけを信頼し、ヨアヒムの答えはそれを釘付けにすると思います。作業を開始する前にサーバーにpingする必要がないという便利さだけを得ました。

関連資料:

26

シンプルです。クライアントに依存して実行したセキュリティメカニズムは、攻撃者がクライアントを制御している場合、侵害される可能性があります。

あなたはクライアントでセキュリティチェックを行うことができますが、「キャッシュ」として効果的に機能するためだけです(次の場合にサーバーへの高価なラウンドトリップを回避するため)クライアントは、答えが「いいえ」になることをすでに知っています。

一連のユーザーからの情報を保持する場合は、それらのユーザーのclientがその情報にアクセスしないようにしてください。 「シークレットデータ」を「表示しないでください」という指示とともに送信すると、そのリクエストをチェックするコードを無効にするのは簡単になります。

ご覧のとおり、この回答ではJavaScript /ブラウザの詳細については触れていません。これは、クライアントが何であっても、この概念は同じだからです。ファットクライアント(従来のクライアント/サーバーアプリ)、旧式のWebアプリケーション、または広範なクライアント側JavaScriptを備えた単一ページアプリであっても、問題にはなりません。

データがサーバーを離れたら、攻撃者がそのサーバーに完全にアクセスできると想定する必要があります。

89
Joachim Sauer

ゲームコミュニティでは、「クライアントは敵の手中にある」という格言があります。サーバーのような安全な領域の外で実行されているコードは脆弱です。最も基本的なシナリオでは、そもそも実行されないことに対して脆弱です。実際に「セキュリティコード」を実行するのはクライアントの決定であり、ユーザーは単に「オプトアウト」する場合があります。ネイティブコードを使用すると、少なくともアセンブリが自動的に難読化され、攻撃者はそれを操作する優れたプログラマーである必要があるという事実による追加の保護層がありますが、JSは通常、難読化されていないプレーンテキストとして提供されます。攻撃をステージングするために必要なのは、プロキシサーバーやテキストエディターなどの原始的なツールだけです。攻撃者は依然としてプログラミングに関するある程度の教育を必要としますが、実行可能ファイルにコードを挿入するよりも、テキストエディターを使用してスクリプトを変更する方が簡単です。

10
nvoigt

これはJavaScriptをハッキングする問題ではありません。アプリを攻撃したい場合は、トラフィックをキャプチャ、変更、および再生できるプライベートプロキシを使用します。提案されたセキュリティスキームは、それに対する保護が適用されていないようです。

1
Mark E. Haase

Angularについて具体的に言えば:

ルートクライアント側の保護は存在しません。ユーザーが常に入力できるルートにボタンを「非表示」にしても、Angularは文句を言いますが、クライアントはその周りにコーディングできます。

ある時点で、コントローラーはビューをレンダリングするために必要なデータをサーバーに要求する必要があります。ユーザーがそのデータへのアクセスを許可されていない場合、サーバー側でこのデータを保護しているため、ユーザーはデータを受信しません。 、そしてあなたのAngularアプリは401を適切に処理する必要があります。

生データを保護しようとしている場合、クライアント側は使用できません。特定のユーザーだけが一般的なデータを特定の方法でしか表示できないようにする場合は、送信するのではなく、サーバー上にデータの「ビュー」を作成します生データをクライアントに送信し、再編成させます(とにかくパフォーマンス上の理由から、これをすでに行っているはずです)。

補足:Angularリクエストであるような、機密性の高いビューテンプレートに組み込まれているリクエストは絶対に行わないでください。何か奇妙な理由がある場合は、これらのビューテンプレートをサーバー側のレンダリングを行う場合と同じように、サーバー側。

0
Mark