Web フロントエンド セキュリティ シリーズ: XSS の攻撃と防御

序文 Web セキュリティの台頭

Web 攻撃技術の開発もいくつかの段階に分けることができます。Web 1.0この時代では、実行可能スクリプト (一般に として知られている) をサーバーにアップロードしてアクセス許可を取得する
など、サーバー側の動的スクリプトのセキュリティ問題にさらに注意が払われていますインジェクションはその後に登場し、インジェクションの出現はセキュリティの歴史における画期的な出来事であり、インジェクションの脆弱性は依然としてセキュリティ分野の重要な部分を占めています。続いて、別のマイルストーンとなるセキュリティ問題(クロスサイト スクリプティング攻撃) が発生しました。の台頭により、 、 などの攻撃がより強力になりました。攻撃の概念もサーバー側からクライアント側、ブラウザーとユーザーに移りました。webshell
SQLSQLWebSQLWebXSSWeb 2.0XSSCSRFWeb

Web今日のテクノロジーの発展により、豊かでカラフルなインターネットが構築されています。インターネット ビジネスの精力的な発展により、 、など
の多くのスクリプト言語も誕生しました。アジャイル開発はインターネットの主要テーマとなっています。携帯電話技術とモバイル インターネットの台頭も、新たな機会と課題をもたらしました。同時に、セキュリティ技術もインターネットの発展と歩調を合わせ、常に新たな変化を進化させていきます。PythonRubyNodeJSHTML 5Web

クロスサイト スクリプティング攻撃 ( XSS) は、クライアント側のスクリプティング セキュリティにおける最大の敵です。脅威は繰り返しリストの上位にOWASP TOP 10挙げられており、この記事では攻撃面と防御面の問題に焦点を当てます。XSS
XSS

予備探査XSS

クロスサイトスクリプティング攻撃、英語の正式名称はCross Site Script、本来の略称は ですが、CSSカスケードスタイルシート(Cascading Style Sheet、 )とCSS区別するため、XSSセキュリティ分野では「 」と呼ばれています。

XSS攻撃とは通常、ハッカーがHTML改ざんされた Web ページを挿入し、ユーザーが Web を閲覧するときにユーザーのブラウザを制御する悪意のあるスクリプトを挿入する攻撃行為を指します。この動作が最初に登場したとき、デモンストレーションのケースはすべてクロスドメイン動作であったため、「クロスサイト スクリプティング」と呼ばれていました。現在、Web端末の機能とアプリケーションが複雑になっているため、クロスサイトであるかどうかは重要ではありませんが、XSSその名前はそのまま残されています。

Web開発の急速な発展に伴い、Web開発は以前のシングルPCエンドから現在のモバイルエンド(APPH5)に至るまで、デスクトップツールや機器の大画面なども含めて広く使用されるようになり、生成されるアプリケーションシナリオはますます増えています。多くの、ますます複雑な状況が存在すると同時に、ほとんどのインターネット (特に伝統的な業界) 製品開発バージョンの反復リリース時間は非常に短く、1 週間に 1 つのバージョンと 2 週間に 1 つの大きなバージョンの場合、セキュリティという重要な属性が無視され、一度攻撃されると悲惨な結果になります。

XSS攻撃タイプの分類

XSS攻撃は、反射型 (非永続的)、ストレージ型 (永続的)、およびベースの 3 つのカテゴリに分類できますDOM XSS

反射性の

反射型は、XSSユーザーが入力したデータを単にブラウザに「反映」するだけです。言い換えれば、ハッカーが攻撃を成功させるには、多くの場合、ユーザーに悪意のあるリンクを「クリック」させる必要があります。反射型は「非持続型XSS」とも呼ばれます( )**XSS****Non-persistent XSS**

通常、Web サイト検索、ジャンプなどのパラメータを渡す機能を介して、反射型XSSの悪意のあるコードが存在します。悪意のある Web サイトを有効にするには、ユーザーが積極的にその Web サイトを開く必要があるため、攻撃者はさまざまな方法を組み合わせてユーザーにクリックを誘導することがよくあります。URLURLURL

最も基本的なリフレクション攻撃の 1 つは、Web ページ データを取得することです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XSS攻防演练</title>
</head>
<body>
    <div id="t"></div>
    <input id="s" type="button" value="这是一个按钮" onclick="test()">
</body>
<script>
    function test() {
      
      
        const arr = ['自定义的数据1', '自定义的数据2', '自定义的数据3', '<img src="11" οnerrοr="console.log(window.localStorage)" />']
        const t = document.querySelector('#t')
            arr.forEach(item => {
      
      
            const p = document.createElement('p')
            p.innerHTML = item
            t.append(p)
        })
    }
</script>
</html>

ハッカーが をクリックすると这是一个按钮、ローカルlocalStorageデータが簡単に取得でき、重要な情報を入手できます。

ストレージタイプ

ストレージ タイプは、XSSユーザーが入力したデータをサーバー側に「保存」します。これはXSS非常に安定しています。

比較的一般的なシナリオは、ハッカーが悪意のあるコードを含むブログ投稿を作成し、記事が公開されると、そのブログ投稿にアクセスしたすべてのユーザーがブラウザでJavaScriptこの悪意のあるコードを実行することです。JavaScriptハッカーは悪意のあるスクリプトをサーバーに保存するため、この種の攻撃は「ストレージ型XSSと呼ばれます**XSS**

<!-- 例如我们分别在网站中的输入框中输入以下信息,并保存到远程数据库 -->
<img src="11" onerror="console.log(window.localStorage)" />
<img src="11" onerror="alert(111)" />

ページ入力
ここに画像の説明を挿入

ここに画像の説明を挿入

alertユーザーがページを参照すると、ポップアップ ボックスがトリガーされ、ローカル データが連続して取得されますlocalStorage
ここに画像の説明を挿入
ここに画像の説明を挿入

上記は典型的なストレージ攻撃です。

に基づくDOM XSS

実はこのタイプはXSS「サーバー側にデータが保存されているかどうか」によって分けられているわけではなく、DOM Based XSS実質的にはそれも反映されていますXSSDOM Based XSSこのタイプは、その形成理由が非常に特殊であり、これを発見したセキュリティ専門家が特にこのタイプを提案したため、別個に分けられますXSSDOM 型 XSS前の 2 つとの違いは、攻撃中に悪意のあるコードの抽出と実行がブラウザによって行われることです。これはXSSフロントエンド自体のセキュリティ脆弱性ですが、他の 2 つはサーバーのセキュリティ脆弱性です。DOM 型 XSSJavaScriptXSS

簡単な例を見てみましょう。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XSS攻防演练</title>
</head>
<body>
    <h3>基于DOM的XSS</h3>
    <input type="text" id="input">
    <button id="btn">提交内容</button>
    <div id="div"></div>
</body>
<script>
    const input = document.getElementById('input');
    const btn = document.getElementById('btn');
    const div = document.getElementById('div');

    let inputValue;
     
    input.addEventListener('change', (e) => {
      
      
        inputValue = e.target.value;
    }, false);

    btn.addEventListener('click', () => {
      
      
        div.innerHTML = `<a href=${ 
        inputValue}>链接地址</a>`
    }, false);
</script>
</html>

ページ上の入力ボックスに次のテキストを入力します'' onclick=alert(/xss/)。ここでの引用符は属性を閉じて null 値を与える''ために使用されます。href次に提交内容ボタンをクリックすると、ページ内のラベルに<div id="div"></div>次のhtmlコンテンツが含まれます

<a href onlick="alert(/xss/)">链接地址</a>

ここに画像の説明を挿入

XSS攻撃防御

防御はXSS非常に複雑ですが、幸いなことに、最新のブラウザーとフロントエンド フレームワーク/ライブラリは、すでに作業のかなりの部分を行ってくれています。

HttpOnly

HttpOnlyこれは最初に Microsoft によって提案され、IE 6中国で実装され、徐々に標準になりました。ブラウザは、属性をJavaScript持つページへのアクセスを禁止しますしたがって、他の方法ではコンテンツを取得できないことをブラウザに知らせるために、応答ヘッダーに設定する必要がありますHttpOnlyCookiehttpset-cookiehttpOnlydocument.cookiecookie

厳密に言えば、事後解決ハイジャック攻撃HttpOnlyに対抗するためのものではありませんしたがって、これを使用すると攻撃を軽減できますが、依然として脆弱性を解決できる他のソリューションが必要です。XSS——HttpOnlyXSSCookieHttpOnlyXSSXSS

入力チェック

ユーザー入力については懐疑的になる必要があります。ユーザーは、入力に対してフィルタリング チェックを行わずに、任意の文字列を入力できます。たとえば、入力すると予想されるコンテンツは次のとおりです。hello wordおそらく受信したコンテンツは ですonclick=alert(/xss/)

防御の観点からXSS、入力チェックでは通常、ユーザーが入力したデータに特殊文字が含まれているかどうかがチェックされます<、>、’、”特殊文字が見つかった場合、これらの文字はフィルタリングまたはエンコードされます。この入力チェックの方法を と呼ぶことができます“XSS Filter”“XSS Filter”インターネット上にはオープンソースの実装が数多くあります。たとえば、単純なhtmlencodeエスケープ:

const htmlEncode = function (handleString){
    
    
    return handleString
    .replace(/&/g,"&amp;")
    .replace(/</g,"&lt;")
    .replace(/>/g,"&gt;")
    .replace(/ /g,"&nbsp;")
    .replace(/\'/g,"&#39;")
    .replace(/\"/g,"&quot;");
}

しかし、入力チェックには次のような欠点もあります。

  • 攻撃者はフロントエンド ページをバイパスし、インターフェイスを直接使用して悪意のあるコードをリモート ライブラリに送信します。
  • 入力データが複数の場所に表示され、それぞれの場所のコンテキストが異なる場合もあり、単一の置換操作を使用すると問題が発生する可能性があります。入力チェックも対象にする必要があり、ある数値が他の数値より小さいことを表現したい場合(3 < 4)、フロントエンドのエスケープ後の文字は となり3 &lt; 4、この値をリモートエンドに格納すると取得されますAJAX。数値計算などを行うと余計なトラブルの原因となります。

出力チェック

一般に、リッチ テキストの出力に加えて、変数をHTMLページに出力する場合、エンコードまたはエスケープを使用してXSS攻撃を防御できます。

XSS の本質は依然として一種の「HTML インジェクション」であり、ユーザー データが HTML コードの一部として実行されるため、元のセマンティクスが混乱し、新しいセマンティクスが生成されます。

入力チェックと同様に、出力をエンコードおよびエスケープできます。

1.HTML出力先

たとえば、HTML コードには次のようなコードがあります。

<div>$htmlVar</div>
<a href="">$htmlVar</a>

出力変数が安全に処理されない場合、出力変数が直接使用され、ページ上にレンダリングされる可能性があり、直接生成につながる可能性がありますXSS最終結果として、次のコードが生成される場合があります。

<div><script>alert('我是一个XSS攻击者')</script></div>
<a href="#"><img href="" onclick="alert('我是另外一个XSS攻击者')"></a>

これを防ぐ方法は、HTML でエスケープ チェックを実行することです。

2.HTMLプロパティへの出力

html 属性が動的な値の場合、exploit 属性も攻撃される可能性があります。

<div id="testXSS" data-name=""></div>

次に、data-nameエスケープされていないコードを属性に挿入すると"><script>alert('我是一个XSS攻击者')</script><"、結果は次のようになります。

<div id="testXSS" data-name=""><script>alert('我是一个XSS攻击者')</script><""></div>

3.<script>ラベルに出力

タグで出力する場合は<script>、まず出力変数が引用符で囲まれていることを確認する必要があります。

<script>
  // 假设userData是攻击者注入的数据
  let xssVar = userData;
</script>

XSS 攻撃を実装するには、攻撃者はまず引用符を閉じる必要があります。

<script>
  // 假设userData是攻击者注入的数据
  let xssVar = "";alert('我是一个script XSS攻击者');
</script>

4.CSS出力先

CSSの作り方は非常に多様でstyleあるため、「ラベル」、「ラベル属性」、「ファイル」には、ユーザーが制御できる変数の出力は原則として可能な限り禁止されています。このような要件が必要な場合は、CSS エスケープ ライブラリを使用することをお勧めします。style attributeXSS<style>HTMLstyleCSS

防衛DOM Based XSS

DOM Based XSSこれは特殊な種類のXSS脆弱性であり、上記のいくつかの防御方法は適用できないため、特別な対応が必要です。要するに、Web サイトのフロントエンド JavaScript コードが十分に厳密ではなく、信頼できないデータがコードとして実行されるのが実際です。

/関数を使用Vue/Reactせずにテクノロジー スタックを使用する場合は、フロントエンド段階で、の隠れた危険性を回避する必要がありますそれについては後ほど専門的な弁護の段落が設けられます。v-htmldangerouslySetInnerHTMLrenderinnerHTMLouterHTMLXSSVueXSS

トリガーとなる箇所は多数ありますが、ページに出力できるのはDOM Based XSS以下の箇所のみです。JavaScriptHTML

  • document.write();
  • document.writeln();
  • xxx.innerHTML();
  • xxx.outerHTML();
  • xxx.innerHTML.replace();
  • document.attachEvent();
  • window.attachEvent();
  • window.location();
  • window.name;

したがって、開発者は、これらの場所のパラメータをユーザーが制御できるかどうかに焦点を当てる必要があります。これらをプロジェクトで使用する場合は、文字列内で信頼できないデータを結合しないようにしてください。

VueでのXSS守備

これをプロジェクトのVueフロントエンド開発フレームワークとして使用すると、おめでとうございます。攻撃の問題Vueのほとんどは解決されますが、攻撃を防ぐためのフレームワークではなく、開発中および使用中に攻撃される脆弱性がまだ残っています。 ;XSSVueXSS

Vueにおける防御策

テンプレートまたはレンダリング関数の使用に関係なく、Vue補間されたコンテンツは、次のテンプレート コードのように自動的にエスケープされます。

<template>
    <p>{
   
   {userData}}</p>
</template>

<script>
    // 从远程获取的数据
    userData = "<script>alert('xss')</script>"
</script>

最終コンパイル後にページに表示されるソース コードの内容はhtml次のとおりです。

<p>
    <script>alert('xss')</script>
</p>

その理由は、Vueデータをエスケープし、スクリプト インジェクションを回避できるようにするためです。このエスケープは textContent などのブラウザネイティブ API を通じて行われるため、ブラウザ自体にセキュリティ ホールがない限り、セキュリティ ホールは発生しません。エスケープされた内容は次のとおりです。

&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;

注射HTML

リモート コンテンツを動的に挿入する場合はHTML、まずコンテンツが安全で有効であることを確認する必要があります。そうでない場合は、いくつかの危険なタグ シンボルをフィルタリングまたはエスケープするための防御措置を講じる必要があります。たとえば、次のようにレンダリングを表示できますHTML

<!-- 当使用模版时 -->
<div v-html="userProvidedHtml"></div>

<!-- 当使用渲染函数时 -->
<script>
    h('div', {
      
      
    domProps: {
      
      
        innerHTML: this.userProvidedHtml
    }
    })
</script>
<!-- 当使用JSX 的渲染函数时 -->
<div domPropsInnerHTML={this.userProvidedHtml}></div>

たとえば、単純な方法を使用することもできます (または、より堅牢なライブラリ/プラグインXSSを参照して、リモートuserProvidedHtmlデータ コンテンツをフィルタリングしてセキュリティを確保することもできます)。

// 一个简单的函数,通过转义<为&lt以及>为&gt来实现防御HTML节点内容
const escape = function(str){
    
    
    return str.replace(/</g, '&lt;').replace(/>/g, '&gt;')
}

スタイルインジェクション

Vueテンプレート内でレンダリングを回避するにはタグを使用しますstyle

<style>{
      
      {
      
       userProvidedStyles }}</style>

これは、一度渡されてもuserProvidedStyles、悪意のあるユーザーがCSS「ログイン」ボタンを覆う透明なボックスとしてリンクをスタイル設定するなど、「クリック詐欺」を提供する可能性があるためです。次に、https://user-XSS-website.com/それをアプリケーションのログイン ページのように見せます。ユーザーの実際のログイン情報を取得する可能性があるため、Vue では、安全に制御できる对象语法特定の値を使用し、ユーザーにのみ提供を許可することをお勧めします。property

<!-- sanitizedUrl应为受控的地址 -->
<a
  v-bind:href="sanitizedUrl"
  v-bind:style="{
    color: userProvidedColor,
    background: userProvidedBackground
  }"
>
  click me
</a>

セキュリティ問題に対する「特効薬」はない

セキュリティ問題を解決する過程では、一度解決することは不可能、つまり「特効薬はない」のです。

一般に、人は面倒なことを嫌い、その面倒をできるだけ遠ざけたいと無意識に願っています。そしてセキュリティというのはやっかいなものであり、避けられない悩みでもあります。セキュリティ問題をきっぱり解決したいと思う人は希望的観測にすぎず、「自分を欺く」のは非現実的です。

ベストプラクティス

一般的なルールとして、フィルタされていないユーザー提供のコンテンツの実行を許可している限り (または)、攻撃される立場に身を置くことになる可能性がありますHTMLこれらの提案は、実際には、 を使用する場合でも、別のフレームワークを使用する場合でも、フレームワークを使用しない場合でも当てはまります。JavaScriptCSSVueReact

参考文献

おすすめ

転載: blog.csdn.net/gaojinbo0531/article/details/129416340