HTTP ハイジャック、DNS ハイジャック、XSSまず、HTTP ハイジャックと DNS ハイジャックとは何かを簡単に説明します。 HTTPハイジャックHTTP ハイジャックとは何ですか? ほとんどの場合、それはオペレータ HTTP ハイジャックです。HTTP リクエストを使用して Web サイトのページを要求すると、ネットワーク オペレータは、慎重に設計されたネットワーク データ パケットを通常のデータ ストリームに挿入して、クライアント (通常はブラウザ) に「間違った」データ (通常はポップアップ、プロモーション広告、または特定の Web サイトのコンテンツを直接表示) を表示させます。誰もがこれに遭遇したことがあるはずです。 DNSハイジャックDNSハイジャックとは、DNSサーバーを乗っ取り、何らかの手段でドメイン名の解決記録を掌握し、このドメイン名の解決結果を改ざんすることで、ドメイン名へのアクセスを元のIPアドレスから改ざんされた指定IPアドレスに転送することです。その結果、特定のURLにアクセスできなくなったり、アクセスしたURLが偽のURLになったりして、データを盗んだり、元の正常なサービスを破壊するという目的を達成します。 DNS ハイジャックは、HTTP ハイジャックよりも極端です。簡単に言うと、リクエストは http://www.a.com/index.html ですが、直接 http://www.b.com/index.html にリダイレクトされます。この記事では、この状況については詳しく説明しません。 XSS クロスサイトスクリプティングXSS とは、攻撃者が脆弱性を悪用して Web ページに悪意のあるコードを挿入することを指します。ユーザーがページを閲覧すると、挿入されたコードが実行され、攻撃の特定の目的が達成されます。 この記事では、これらの攻撃がどのように生成されるか、または攻撃者が悪意のあるコードをページに挿入する方法については説明しません。HTTP ハイジャックと XSS は、最終的にはクライアント側 (通常はユーザーのブラウザ) で実行される悪意のあるコードであることを知っていれば十分です。この記事では、挿入がすでに存在することを前提として、フロントエンド保護を効果的に行うために JavaScript を使用する方法について説明します。 ページはiframeに埋め込まれており、iframeをリダイレクトしますまず、ページが iframe に埋め込まれている状況について説明します。つまり、埋め込まれた広告が元のウェブサイトのページに与える影響を最小限に抑えるために、ネットワーク オペレーターは通常、元のウェブサイトのページを元のページと同じサイズの iframe に配置し、iframe を使用して元のページへの広告コードの影響を分離できるようにします。 この状況は比較的簡単に対処できます。ページが iframe 内にネストされているかどうかを知る必要があります。ネストされている場合は、外側のページを通常のページにリダイレクトします。 では、ページが現在 iframe 内に存在しているかどうかを知る方法はあるのでしょうか?はい、window.self と window.top です。 ウィンドウ自身 現在のウィンドウ オブジェクトへの参照を返します。 ウィンドウ上部 ウィンドウ階層の最上位のウィンドウへの参照を返します。 同一オリジンでないドメイン名の場合、iframe 子ページは parent.location または top.location を通じて特定のページ アドレスを取得することはできませんが、top.location に書き込むことはできます。つまり、親ページのジャンプを制御できます。 2 つの属性はそれぞれ self と top と省略できるため、ページが iframe 内にネストされていることがわかった場合は、親ページをリダイレクトできます。 (自分!=トップ)の場合{ // 通常のページ var url = location.href; // 親ページのリダイレクト top.location = url; } ホワイトリストを使用して通常の iframe ネストを許可するもちろん、多くの場合、おそらく運用上のニーズにより、ページはさまざまな方法で宣伝されたり、通常のビジネス ニーズのために iframe にネストされたりすることがあります。このとき、ホワイト リストまたはブラック リストが必要です。ページが iframe にネストされ、親ページのドメイン名がホワイト リストに含まれている場合、リダイレクト操作は実行されません。 前述の通り、top.location.href では親ページの URL を取得できません。この場合は document.referrer を使用する必要があります。 クロスドメイン iframe 親ページの URL は、document.referrer を通じて取得できます。 // ホワイトリストを作成する var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; (自分!=トップ)の場合{ var // document.referrer を使用して、クロスドメイン iframe の親ページの URL を取得します。 親Url = document.referrer、 長さ = whiteList.length、 私 = 0; for(; i<長さ; i++){ // ホワイトリスト正規表現を作成する var reg = new RegExp(whiteList[i],'i'); // ホワイトリストに存在する場合は解放します if(reg.test(parentUrl)){ 戻る; } } // 通常のページ var url = location.href; // 親ページのリダイレクト top.location = url; } URLパラメータを変更してオペレータタグをバイパスするそれだけですか?いいえ、親ページをリダイレクトしましたが、リダイレクト プロセス中に最初にネストされたため、このリダイレクト プロセス中にページが iframe によって再度ネストされる可能性があり、これは非常に煩わしいです。 もちろん、オペレーターによるこのようなハイジャックは通常、痕跡を残します。最も一般的な方法は、http://www.example.com/index.html?iframe_hijack_redirected=1 などのページ URL にパラメータを設定することです。iframe_hijack_redirected=1 は、ページがハイジャックされ、iframe がネストされていないことを意味します。したがって、この機能に基づいて、URL を書き換えて、ハイジャックされたように見せることができます。 var フラグ = 'iframe_hijack_redirected'; // 現在のページは iframe 内に存在する // ここでホワイトリストのマッチングルールを確立する必要があり、ホワイトリストはデフォルトで解放される if (self != top) { var // document.referrer を使用して、クロスドメイン iframe の親ページの URL を取得します。 親Url = document.referrer、 長さ = whiteList.length、 私 = 0; for(; i<長さ; i++){ // ホワイトリスト正規表現を作成する var reg = new RegExp(whiteList[i],'i'); // ホワイトリストに存在する場合は解放します if(reg.test(parentUrl)){ 戻る; } } var url = location.href; var parts = url.split('#'); if (location.search) { パーツ[0] += '&' + フラグ + '=1'; } それ以外 { パーツ[0] += '?' + フラグ + '=1'; } 試す { console.log('ページはiframeに埋め込まれています:', url); top.location.href = parts.join('#'); } キャッチ (e) {} } もちろん、このパラメータを変更すると、ネスト防止コードは無効になります。そのため、報告システムも確立する必要があります。ページがネストされていることがわかったら、傍受レポートを送信します。リダイレクトが失敗した場合でも、iframe に埋め込まれたページの URL を知ることができます。これらの URL を分析することで、後述する保護対策を継続的に強化できます。 インラインイベントとインラインスクリプトインターセプションXSS では、特に HTML5 のリリース以降、スクリプトを挿入する方法が実際にたくさんあります。注意しないと、多くの新しいタグを使用して実行可能なスクリプトを挿入できます。 一般的な注入方法をいくつか挙げます。 1. <a href="javascript:alert(1)" rel="external nofollow" _fcksavedurl="javascript:alert(1)" ></a> 2. <iframe src="javascript:alert(1)" /> 3. <img src='x' onerror="アラート(1)" /> 4. <video src='x' onerror="アラート(1)" ></video> 5. <div onmouseover="alert(2)" ><div> ここにリストされていない非常にまれでわかりにくい注入メソッドを除いて、そのほとんどは javascript:... およびインライン イベント on* です。 インジェクションがすでに発生していると仮定した場合、これらのインライン イベントとインライン スクリプトの実行を傍受する方法はありますか? 上記のスクリプト(1)と(5)は、実行前にユーザーがクリックしたり、何らかのイベントを実行したりする必要があるため、それらに対して防御する方法があります。 ブラウザイベントモデルここで言及されている傍受機能には、イベント モデルに関連する原則が関係します。 標準のブラウザ イベント モデルには 3 つのステージがあることは誰もが知っています。
<a href="javascript:alert(222)" rel="external nofollow" rel="external nofollow" _fcksavedurl="javascript:alert(222)" ></a> のようなタグの場合、実際にトリガーされる要素 alert(222) は、クリック イベントのターゲット フェーズにあります。 <a href="javascript:alert(222)" rel="external nofollow" rel="external nofollow" >クリックしてください</a> <スクリプト> document.addEventListener('click', 関数(e) { 警告(111); }、 真実); </スクリプト> 上記の「click me」をクリックすると、最初に 111 がポップアップ表示され、次に 222 が表示されます。 次に、クリック イベント モデルのキャプチャ フェーズ中にタグ内の javascript:... コンテンツのキーワード ブラックリストを作成し、それをフィルタリングして確認するだけで、必要なインターセプト効果が得られます。 on* タイプのインライン イベントについても同様ですが、このようなイベントは多すぎるため、手動で列挙することはできません。コードを使用して、インライン イベントとインライン スクリプトを自動的に列挙およびインターセプトすることができます。 a タグ内の href="javascript:..." のインターセプションを例にとると、次のように記述できます。 // キーワードブラックリストを作成する var keywordBlackList = [ 'xss', 'BAIDU_SSP__ラッパー', 'BAIDU_DSPUI_FLOWBAR' ]; document.addEventListener('click', 関数(e) { var コード = ""; // スクリプトをスキャンします for <a href="javascript:" rel="external nofollow" > if (elem.tagName == 'A' && elem.protocol == 'javascript:') { var code = elem.href.substr(11); if (blackListMatch(キーワードBlackList, コード)) { // ログアウトコード elem.href = 'javascript:void(0)'; console.log('疑わしいイベントを傍受します:' + code); } } }、 真実); /** * [ブラックリストマッチ] * @param {[Array]} blackList [ブラックリスト] * @param {[String]} value [検証する文字列] * @return {[Boolean]} [false -- 検証失敗、true -- 検証合格] */ 関数 blackListMatch(blackList, 値) { var 長さ = blackList.length、 私 = 0; (; i < 長さ; i++) { // ブラックリスト正規表現を作成する var reg = new RegExp(whiteList[i], 'i'); // ブラックリストに存在する場合はインターセプトします if (reg.test(value)) { true を返します。 } } false を返します。 } 画像内のボタンをクリックすると、次の内容が表示されます。 ここではブラックリスト マッチングを使用します。これについては以下で詳しく説明します。 静的スクリプトのブロックXSS クロスサイト スクリプティングの本質は、「クロスサイト」ではなく「スクリプティング」です。 一般的に、攻撃者またはオペレーターはページに <script> スクリプトを挿入し、特定の操作はすべてスクリプトに実装されます。このハイジャック手法では、挿入は 1 回だけで済み、変更があった場合でも毎回再挿入する必要はありません。 <script src="http://attack.com/xss.js"> スクリプトがページに挿入されていると想定し、このスクリプトの実行を傍受することを目標とします。 難しそうですね。どういう意味ですか?目的は、疑わしいスクリプトが実行される前に検出し、内部コードを実行できないように破壊することです。 したがって、ページが読み込まれたときに生成されたノードを検出するには、いくつかの高度な API を使用する必要があります。 ミューテーションオブザーバー MutationObserver は、HTML5 に追加された強力な新しい API です。これにより、開発者は特定の範囲内の DOM ツリーが変更されたときに適切に対応できるようになります。 非常に神秘的に聞こえますが、大まかに言うと、ページの DOM ツリーの変更を監視し、それに応じて応答できることを意味します。 MutationObserver() このコンストラクターは、新しい Mutation オブザーバー オブジェクトをインスタンス化するために使用されます。 ミューテーションオブザーバー 関数コールバック ); 私はびっくりしました。この長い文章は何について書いてあるのでしょうか?つまり、MutationObserver が監視する場合、新しい要素が見つかったときにすぐにコールバックするのではなく、時間セグメントに出現するすべての要素を一緒に渡します。したがって、コールバックでバッチ処理を行う必要があります。また、指定した DOM ノード (ターゲット ノード) が変更されたときに したがって、MutationObserver を使用すると、ページによって読み込まれる各静的スクリプト ファイルを監視できます。 // MutationObserver のさまざまな互換性書き込み方法 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || ウィンドウ.MozMutationObserver; // このコンストラクタは、新しい Mutation オブザーバ オブジェクトをインスタンス化するために使用されます // Mutation オブザーバ オブジェクトは、特定の範囲内で DOM ツリーの変更を監視できます var observer = new MutationObserver(function(mutations) { 変異.forEach(関数(変異) { // 追加されたノード、または null を返します。 var ノード = mutation.addedNodes; (var i = 0; i < nodes.length; i++) の場合 { var ノード = ノード[i]; (/xss/i.test(node.src))) の場合 { 試す { ノードの親ノードを削除します。 console.log('疑わしい静的スクリプトをインターセプトします:', node.src); } キャッチ (e) {} } } }); }); // ターゲットノードと観測オプションを渡す // ターゲットが document または document.documentElement の場合 // 現在のドキュメント内のすべてのノードの追加と削除操作が監視されます observer.observe(document, { サブツリー: true、 子リスト: true }); <script type="text/javascript" src="./xss/a.js"></script> は、ページ読み込みの最初に存在する静的スクリプトです (ページ構造を参照)。スクリプトの読み込みから実行までの間、MutationObserver を使用してそのコンテンツに対して正規表現マッチングを実行します。悪意のあるコードが見つかった場合は、removeChild() を使用して実行できないようにします。 ホワイトリストを使用してsrcと一致させる上記のコードでは、次の文を使用して、js スクリプトが悪意のあるものであるかどうかを判断します。 (/xss/i.test(node.src)) の場合 {} もちろん、現実には、悪意のあるコードを挿入する人は、名前を XSS に変更するほど愚かではありません。そのため、フィルタリングにはホワイトリストを使用し、傍受および報告システムを確立する必要があります。 // ホワイトリストを作成する var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; /** * [ホワイトリストマッチング] * @param {[Array]} whileList [ホワイトリスト] * @param {[String]} value [検証する文字列] * @return {[Boolean]} [false -- 検証失敗、true -- 検証合格] */ 関数 whileListMatch(whileList, 値) { var 長さ = whileList.length, 私 = 0; (; i < 長さ; i++) { // ホワイトリスト正規表現を作成する var reg = new RegExp(whiteList[i], 'i'); // ホワイトリストに存在する場合は解放する if (reg.test(value)) { true を返します。 } } false を返します。 } // ホワイトリストのみ解放 if (!whileListMatch(blackList, node.src)) { ノードの親ノードを削除します。 } ここではホワイトリストのマッチングについて何度か説明しましたが、これは以下でも再度使用されるため、ここではメソッド呼び出しにカプセル化することができます。 動的スクリプトブロックMutationObserver は、静的スクリプトをインターセプトするために上記で使用されています。静的スクリプトに加えて、対応するものは動的に生成されるスクリプトです。 var スクリプト = document.createElement('script'); スクリプトタイプ = 'text/javascript'; スクリプトのソースを 'http://www.example.com/xss/b.js' に変更します。 document.getElementsByTagName('body')[0].appendChild(スクリプト); このタイプの動的に生成されたスクリプトをインターセプトするには、インターセプトのタイミングを DOM ツリーに挿入されたとき、実行前とする必要があるため、Mutation Events の DOMNodeInserted イベントをリッスンできます。 ミューテーションイベントとDOMNodeInsertedMDN を開くと、最初の文は次のようになります。 この機能は Web 標準から削除されました。一部のブラウザではまだサポートされていますが、将来的にはサポートされなくなる可能性があります。この機能は使用しないようにしてください。 利用できませんが、次のことは理解できます: document.addEventListener('DOMNodeInserted', 関数(e) { var ノード = e.target; if (/xss/i.test(node.src) || /xss/i.test(node.innerHTML)) { ノードの親ノードを削除します。 console.log('疑わしい動的スクリプトをインターセプトします:', node); } }、 真実); 残念ながら、上記のコードは動的に生成されたスクリプトを傍受できますが、コードも実行されます。DOMNodeInserted は、その名前が示すように、DOM 範囲内の構造変更を監視できます。MutationObserver と比較すると、より早く実行されます。 ただし、DOMNodeInserted は推奨されなくなったため、動的スクリプトを監視するタスクも MutationObserver に引き継ぐ必要があります。 残念ながら、実際には MutationObserver を使用した結果は DOMNodeInserted と同じになります。動的スクリプトの生成を監視および傍受できますが、スクリプトが実行される前に removeChild を使用して削除することはできないため、他の方法を考える必要があります。 setAttribute と document.write をオーバーライドするネイティブのElement.prototype.setAttributeメソッドをオーバーライドする動的スクリプトが挿入され実行される前は、DOM ツリーの変更を監視してそれを傍受することはできず、スクリプトは実行されます。 次に、スクリプトが作成されるときに、スクリプトが DOM ツリーに挿入される前に、スクリプトを検索してキャプチャする必要があります。 次のような動的スクリプトが作成されたとします。 var スクリプト = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', 'http://www.example.com/xss/c.js'); document.getElementsByTagName('body')[0].appendChild(スクリプト); Element.prototype.setAttribute を書き換えることも可能です。ここでは setAttribute メソッドが使用されていることがわかります。このネイティブ メソッドを書き換えて、src 属性を設定するときに値をリッスンし、ブラックリストまたはホワイトリストを通じて判断できれば、タグの正当性を判断できます。 // 元のインターフェースを保存します var old_setAttribute = Element.prototype.setAttribute; // setAttributeインターフェースを書き換える Element.prototype.setAttribute = function(name, value) { // <script src='xxx' > 型に一致 if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) { // ホワイトリストのマッチングif (!whileListMatch(whiteList, value)) { console.log('疑わしいモジュールをインターセプトします:', value); 戻る; } } //元のインターフェース old_setAttribute.apply(this, arguments); を呼び出します。 }; // ホワイトリストを作成する var whiteList = [ 'www.yy.com', 'res.cont.yy.com' ]; /** * [ホワイトリストマッチング] * @param {[Array]} whileList [ホワイトリスト] * @param {[String]} value [検証する文字列] * @return {[Boolean]} [false -- 検証失敗、true -- 検証合格] */ 関数 whileListMatch(whileList, 値) { var 長さ = whileList.length, 私 = 0; (; i < 長さ; i++) { // ホワイトリスト正規表現を作成する var reg = new RegExp(whiteList[i], 'i'); // ホワイトリストに存在する場合は解放する if (reg.test(value)) { true を返します。 } } false を返します。 } Element.prototype.setAttribute を書き換えます。つまり、最初に元のインターフェースを保存し、要素が setAttribute を呼び出すときに、渡された src がホワイトリストに存在するかどうかを確認します。存在する場合は解放されます。存在しない場合は、疑わしい要素とみなされ、報告されて実行されません。最後に、解放された要素に対してネイティブの setAttribute が実行されます (つまり、old_setAttribute.apply(this, arguments);)。 上記のホワイトリスト マッチングは、ブラックリスト マッチングに置き換えることもできます。 ネストされた iframe 内で Element.prototype.setAttribute をオーバーライドするもちろん、old_setAttribute = Element.prototype.setAttribute が攻撃者に公開されている場合、old_setAttribute を直接使用するとオーバーライドされたメソッドをバイパスできるため、このコードはクロージャでラップする必要があります。 もちろん、現在のウィンドウの Element.prototype.setAttribute がオーバーライドされているとしても、これは安全ではありません。しかし、ネイティブの Element.prototype.setAttribute を取得する方法はまだあります。必要なのは新しい iframe だけです。 var newIframe = document.createElement('iframe'); document.body.appendChild(新しいIframe); Element.prototype.setAttribute = newIframe.contentWindow.Element.prototype.setAttribute; この方法を使用すると、iframe 内の環境と外部ウィンドウが完全に分離されるため、ネイティブの Element.prototype.setAttribute を再度取得できます。何だって? 何をするか? createElement は iframe の作成に使用されているようですが、ネイティブの createElement を書き換えることは可能でしょうか?しかし、createElement の他に createElementNS もあり、ページ上に iframe が既に存在する可能性があるため、適切ではありません。 その後、新しい iframe が作成されるたびに、setAttribute が保護されて書き換えられ、ここで MutationObserver が再度使用されます。 /** * MutationObserverを使用して生成されたiframeページを監視します。 * 内部ネイティブの setAttribute と document.write の呼び出しを防止 * @return {[type]} [説明] */ 関数defenseIframe() { // 最初に現在のページを保護します installHook(window); } /** * 単一ウィンドウのsetAttribute保護を実装する* @param {[BOM]} window [ブラウザウィンドウオブジェクト] * @return {[type]} [説明] */ 関数 installHook(window) { // 単一ウィンドウの setAttribute プロパティを書き換えます resetSetAttribute(window); // MutationObserver のさまざまな互換性記述方法 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; // このコンストラクタは、新しい Mutation オブザーバ オブジェクトをインスタンス化するために使用されます // Mutation オブザーバ オブジェクトは、特定の範囲内で DOM ツリーの変更を監視できます var observer = new MutationObserver(function(mutations) { 変異.forEach(関数(変異) { // 追加されたノード、または null を返します。 var ノード = mutation.addedNodes; // 1つずつ走査する for (var i = 0; i < nodes.length; i++) { var ノード = ノード[i]; // 生成されたiframe環境に書き換えフックをインストールします。if (node.tagName == 'IFRAME') { インストールフック(node.contentWindow); } } }); }); オブザーバー.観察(ドキュメント, { サブツリー: true、 子リスト: true }); } /** * 単一ウィンドウの setAttribute プロパティをオーバーライドします * @param {[BOM]} window [ブラウザウィンドウオブジェクト] * @return {[type]} [説明] */ 関数 resetSetAttribute(window) { //元のインターフェースを保存します var old_setAttribute = window.Element.prototype.setAttribute; // setAttributeインターフェースを書き換える window.Element.prototype.setAttribute = function(name, value) { ... }; } ウィンドウをパラメータとして installHook メソッドを定義します。このメソッドでは、渡されたウィンドウの setAttribute をオーバーライドし、MutationObserver をインストールして、将来このウィンドウに作成される可能性のある iframe を監視します。将来このウィンドウに iframe が作成されると、レイヤーごとの保護を提供するために、新しい iframe にも installHook メソッドがインストールされます。 document.write をオーバーライドする上記の方法に基づいて、ページをより適切に保護するために書き換えることができる他の方法を引き続き調査できます。 Document.write は非常に良い選択です。インジェクション攻撃者は通常、この方法を使用してページにポップアップ広告を挿入します。 document.write を書き換えて、キーワード ブラックリストを使用してコンテンツを一致させることができます。 ブラックリストに登録するのに適したキーワードは何ですか?広告がたくさんあるページをいくつか見てみましょう。 ここでは、広告コードを含む iframe がページの下部に埋め込まれています。ここで最も外側の ID 名 id="BAIDU_SSP__wrapper_u2444091_0" は、悪意のあるコードかどうかを判断するための良い指標です。傍受レポートに基づいてブラックリストのバッチを収集したと仮定します。 // 通常の傍受キーワードを作成する var keywordBlackList = [ 'xss', 'BAIDU_SSP__ラッパー', 'BAIDU_DSPUI_FLOWBAR' ]; 次に、これらのキーワードを使用して、document.write によって渡されたコンテンツに対して正規表現判定を実行し、document.write コードをインターセプトするかどうかを決定するだけです。 // キーワードブラックリストを作成する var keywordBlackList = [ 'xss', 'BAIDU_SSP__ラッパー', 'BAIDU_DSPUI_FLOWBAR' ]; /** * 単一ウィンドウの document.write プロパティをオーバーライドします * @param {[BOM]} window [ブラウザウィンドウオブジェクト] * @return {[type]} [説明] */ 関数 resetDocumentWrite(window) { var old_write = window.document.write; window.document.write = 関数(文字列) { if (blackListMatch(キーワードBlackList, 文字列)) { console.log('疑わしいモジュールをインターセプトします:', string); 戻る; } //元のインターフェースを呼び出します old_write.apply(document, arguments); } } /** * [ブラックリストマッチ] * @param {[Array]} blackList [ブラックリスト] * @param {[String]} value [検証する文字列] * @return {[Boolean]} [false -- 検証失敗、true -- 検証合格] */ 関数 blackListMatch(blackList, 値) { var 長さ = blackList.length、 私 = 0; (; i < 長さ; i++) { // ブラックリスト正規表現を作成する var reg = new RegExp(whiteList[i], 'i'); // ブラックリストに存在する場合はインターセプトします if (reg.test(value)) { true を返します。 } } false を返します。 } 上記の installHook メソッドに resetDocumentWrite を配置すると、現在のウィンドウと生成されたすべての iframe 環境の document.write を書き換えることができます。 ロック適用と呼び出し次に紹介するのは、ネイティブの Function.prototype.apply メソッドと Function.prototype.call メソッドのロックです。ロックとは、オーバーライドできないようにすることを意味します。 ここでは、適用と呼び出しをロックするために Object.defineProperty が使用されます。 オブジェクト.defineProperty Object.defineProperty() メソッドは、オブジェクトに直接新しいプロパティを定義するか、既存のプロパティを変更して、オブジェクトを返します。 オブジェクト.defineProperty(obj, prop, 記述子) で:
次のコードを使用すると、call と apply が書き換えられるのを防ぐことができます。 // ロック呼び出し Object.defineProperty(Function.prototype, 'call', { 値: Function.prototype.call、 // このプロパティは、このプロパティの書き込み可能が true の場合にのみ、代入演算子によって変更できます。書き込み可能: false、 // このプロパティは、configurable が true の場合にのみ変更および削除できます。configurable: false、 列挙可能: true }); // ロックを適用 Object.defineProperty(Function.prototype, 'apply', { 値: Function.prototype.apply、 書き込み可能: false、 設定可能: false、 列挙可能: true }); なぜこのように書くのでしょうか?実は、これは上記の setAttribute の書き換えとまだ関連しています。 元の Element.prototype.setAttribute をクロージャに保存しましたが、クロージャからそれを「盗む」ためのトリックがまだいくつかあります。 これを試してください: (関数() {})( // 元のインターフェースを保存します var old_setAttribute = Element.prototype.setAttribute; // setAttributeインターフェースを書き換える Element.prototype.setAttribute = function(name, value) { // 詳細 if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {} //元のインターフェース old_setAttribute.apply(this, arguments); を呼び出します。 }; )(); // 書き換えを適用 Function.prototype.apply = function(){ console.log(これを); } // setAttribute を呼び出す document.getElementsByTagName('body')[0].setAttribute('data-test','123'); 上記の段落では何が出力されると思いますか?見てみましょう: 実際にはネイティブの setAttribute メソッドが返されました。 これは、Element.prototype.setAttribute を書き換えると、最後に、apply メソッドを使用する old_setAttribute.apply(this, arguments); があるためです。したがって、apply を書き換えて、これを出力します。書き換えた setAttribute を呼び出すと、そこから元の保存された old_setAttribute を取得できます。 このように、上で行ったネストされた iframe の setAttribute の書き換えは無意味になります。 上記の Object.defineProperty を使用すると、apply や同様の呼び出しがブロックされる可能性があります。書き換え不可能にして、ネイティブ インターフェイスがクロージャから盗まれないようにします。そうして初めて、書き換えたいプロパティが正常に書き換えられたと言えます。 傍受レポートの作成これで防御策がいくつかできました。次に、上記のテキストの console.log() ログを置き換えるレポート システムを構築する必要があります。 報告システムの用途は何ですか?当社ではホワイトリストとキーワード ブラックリストを使用しているため、これらのデータを継続的に充実させる必要があり、傍受した各情報をサーバーに送信するレポート システムに依存しています。これにより、当社のプログラマーは攻撃の発生を最初に知ることができるだけでなく、より適切な対応のために関連情報を継続的に収集することもできます。 この例では、Node.js を使用して、http レポート要求を受け入れるための非常にシンプルなサーバーを構築します。 まずレポート関数を定義します。 /** * カスタムレポート - ページ内の console.log() を置き換えます * @param {[String]} name [インターセプションタイプ] * @param {[String]} value [切片値] */ 関数hijackReport(名前, 値) { var img = document.createElement('img')、 hijackName = 名前、 hijackValue = value.toString()、 curDate = 新しい Date().getTime(); // レポート img.src = 'http://www.reportServer.com/report/?msg=' + hijackName + '&value=' + hijackValue + '&time=' + curDate; } サーバー アドレスが www.reportServer.com であると仮定すると、img.src を使用して、カスタム インターセプト タイプ、インターセプト コンテンツ、レポート時刻を指定した HTTP 要求をサーバー http://www.reportServer.com/report/ に送信します。 Express を使用して Node.js サーバーを構築し、簡単な受信ルートを記述します。 var express = require('express'); var app = express(); app.get('/report/', 関数(req, res) { var queryMsg = req.query.msg, クエリ値 = 要求クエリ値、 queryTime = 新しい Date(parseInt(req.query.time)); if (クエリメッセージ) { console.log('インターセプションタイプ: ' + queryMsg); } if (クエリ値) { console.log('インターセプト値: ' + queryValue); } if (クエリ時間) { console.log('インターセプト時間: ' + req.query.time); } }); app.listen(3002, 関数() { console.log('HttpHijack サーバーがポート 3002 でリッスンしています!'); }); サーバーを実行し、レポートが発生すると、次のデータが受信されます。 さて、次のステップは、データを保存し、分析し、ブラックリストに追加し、Node.js を使用し、もちろん傍受が発生したときにプログラマーに通知するメールを送信することです。これについては詳しく説明しません。 HTTPS と CSP最後に、HTTPS と CSP について簡単に説明します。実際、フロントエンドでできることはほとんどないため、ハイジャックを防御する最善の方法は、バックエンドから始めることです。また、ソースコードが公開されているため、攻撃者は簡単に防御対策を回避できます。 CSPCSP は Content Security Policy の略で、コンテンツ セキュリティ ポリシーと翻訳されます。この仕様はコンテンツのセキュリティに関連しており、主に XSS の発生を減らすためにページが読み込むことができるリソースを定義するために使用されます。 MDN – CSP 翻訳HTTP ハイジャックが実行できる根本的な理由は、HTTP プロトコルには通信相手の ID とデータの整合性を検証する方法がないことです。この問題が解決されれば、ハイジャックは簡単には起こらなくなるでしょう。 HTTPS は HTTP over SSL を意味します。 SSL プロトコルは、トランスポート層のセキュリティ問題を解決するために 1995 年に Netscape によって初めて提案されたネットワーク プロトコルです。その中核は公開鍵暗号化の理論に基づいており、サーバー ID 認証、データ プライバシー保護、データ整合性検証などの機能を実装します。 この記事のメインの内容とは関係がないので、CSP と HTTPS の詳細については Google で検索してください。 上記は、フロントエンドセキュリティ JavaScript アンチ http ハイジャックおよび XSS の詳細な説明です。フロントエンドセキュリティ JavaScript アンチ http ハイジャックおよび XSS の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: 「いいね!」文がインデックスに登録されないのはなぜですか?
序文こういう特殊効果ってよく見かけますよね。すごくかっこいいですよね。 これは、Google Mat...
MySQL 5.7 バージョン:方法1: SET PASSWORDコマンドを使用するフォーマット: ...
効果環境が必要ビュー要素UIドラッグアンドドロッププラグインSortable.js必要な構成プロパテ...
目次LAMPアーキテクチャ1.ランプの紹介2. WebサービスワークフローWebサーバーのリソースは...
DOMとは何ですか? JavaScript を使用すると、HTML ドキュメント全体を再構築できます...
Web ページの外観はレイアウトに大きく左右されます。ページ内に長い段落のテキストがある場合、通常は...
目次01 シナリオ分析02 操作方法03 結果分析01 シナリオ分析今日の午後、開発仲間がオンライン...
偶然、プロジェクト内でVue.$setが無効であることがわかりましたデータ フィルタリングを追加する...
さっそく、コードを直接投稿します。具体的なコードは次のとおりです。 <html> <...
序文MySQLでは、準備、実行、割り当て解除を正式にはPREPARE STATEMENTと呼びます。...
目次例示する1. ブロブオブジェクト2. フロントエンド3. バックエンド要約する例示する最近、ファ...
雇用主から MySQL クエリ条件でインデックスが使用されるかどうかを尋ねられた場合、どのように答え...
dokekrでmysqlコンテナを起動するコマンドを使用します: docker run -p 330...
1. スロークエリの用途は何ですか? long_query_time を超えて実行されるすべての S...
目次1. nodejsをダウンロードする2. ダブルクリックしてインストール3. グローバル npm...