XSSの本質を10分で体系的に理解【覚書】



セキュリティの用語ってわからなくないですか?

重要って言う割には、本質の部分を説明されていないのか、自分が馬鹿なのかわからなく、

けっきょく毎回読みなおして時間を取られてしまう。。。

ちょっと時間をとって本質となる筋を整理してみようとトライしました。

XSS(クロス サイト スクリプティング)とは?

XSSとは

Aサイトから、Bサイトへスクリプト攻撃ができること?


ここがもやっとしていること。

なのでまずは、よくあるパターンから、XSSのリアルな定義(実現可能な方法)を明確にしていきたいと思います。

そもそも今どき、JavaScriptは他サイトへ連携できません。Cockieも自サイトの情報しか取得できません。

(広い意味では、大きな掲示板で、aaスレッドから zzスレッドを見る場合クロスサイトっぽいですが、クロスサイトではないし、単にそのサイトに閉じた脆弱性です)

Get リクエストはユーザのブラウザ経由でできます(Linkクリックと同じ状態)

 

ケース1:ある掲示板に悪意のあるスクリプトが埋め込まれる

クロスサイトではなく、サイトの脆弱性。もちろん出力時にサニタイジングすれば利便性は置いておいて、とりあえず対策としてOK。

単純には、XSSよりも、JSインジェクション。
もちろんSQLインジェクションになりえる可能性もある。このページでは深堀しない。

派生ケース:フィッシング画面(銀行のログインそっくり画面など)を表示する。他の悪意のあるサイトに飛ばす。

悪意のあるサイト開いても、今はウイルスにはまずかかりません。ボタンを押してもそう簡単に直接インストールできないようになっています。もちろんメアドや電話番号、クレジットカード番号などわかるはずもありませんし、他サイト(ドメインが異なる)であるFaceBookに入力した情報など取れません。

他のサイトでスクリプトを実行。はできない。

GETで画面遷移できるのみ(結構柔軟性があるが)。もうひとつの別サイトで、削除処理とかPW変更処理などが URIだけでできてしまうと問題がある。ページ遷移を必要とするなどで防げる(PWを再度聞く、amazon/yahooなどのやり方など)
これは XSSではなく CSRF(クロスサイト  リクエストフォージェリ)

 

ケース2:悪意のあるサイトに行って、クロスサイトスクリプトを埋め込まれる。

いろいろ突っ込みどころが満載。
そもそも悪意のあるサイトに行くなというのがある。行ってもダイレクトにサイトをまたがって実行されないし、ユーザを誘導することは難しい。スクリプトを実行しても、ブラウザやOSを不安定に多少できるぐらい。最近はブラウザ・OSでも対策されているのでちょっとやそっとで全体まで巻き添えを食わない。

XSS部分は実行不可スクリプトを潜伏させられない
CSRSとして、もう一方のサイトにメッセージをスクリプト込みで出力させることはできなくはない。
そのもう一方のサイトがスクリプト対策をしていないと、そのサイトを見たユーザの情報のうち、JSを実行できてしまうとWEB操作のだいたいのことができる。そのサイトに入れた情報で遷移直後の1ページ分やクッキー情報だけは、動的URLアクセスで悪意のあるデータ蓄積サイトにURL GETのふりをして送ることが可能。

つまり、自サイト以外から更新をできて、ユーザの入力(意図的、不意関わらず)でJSの処理を自由にさせなければいい

実践上の突っ込み

悪意のサイトに来てもらうより、そもそもそのターゲットサイトに直接記載したほうが早い。
シークレット気味の情報であればURLが不明。可能性の残りはユーザ独自の画面の情報を悪意のある人がほしい時だけ。これにたいしては、ユーザ独自の画面の情報やcockieはワンクッションおくページにすれば、XSSではひっかからなく、そもそもXSS以前の問題なので、XSSという範疇で語るのも違和感がある。まぁ サニタイジングしておけば十分なのは変わらないけど。

対策として

複数人で書いたり、見たりするページは JSインジェクションなどをしておく。(セキュリティ的にはSQLインジェクション対策、httpsによる漏洩対策など、やることはいろいろあるがいったん置いておく)

セッションハイジャックも、IPアドレスチェックと2往復以上やったり、Webページの遷移情報やタイムアウト処理をすればcookie取られても、肝心の情報はとられないと思うが、
セッション管理のアルゴリズムはよくわからないので(ソースを見ればわかるかも)イマイチ担保はできないが、

つまり

XSSとは、実践的にはあるサイトで情報を持っていて、わるもんが情報を取得したいケースかまたは愉快犯である。

スクリプトを潜伏させることは WebExtensionなどの拡張機能経由や、すでにウイルスにかかっている場合でない限り基本無理。またスクリプト埋め込みのURLリダイレクトは、サイトを見るまでのラグはあるかもしれないがすぐ発動する。

2つのサイトの立場での対応がある。ひとつはユーザの入力を柔軟にさせ過ぎないこと(入力チェックと出力チェック(主に後者がサニタイジング対象となる箇所))。もうひとつはユーザ情報の出力や変更処理の個所。ここにおいて外部からワンアクションでなるべく処理させないこと。重要なクレカやPW情報は必ず2ページ以上の手動遷移などがいいと思う。

フィッシング系やウイルス系、物理的な面の情報漏洩や盗難、またはPW漏洩などは各個人での対策が必要。

XSSと言っても、何でもかんでも情報がとられたり乗っ取られることは、あまりない。


XSS対策→出力時のユーザ入力内容のサニタイジング   or  他サイトからの情報の書き換え防止   or  ユーザ情報に対する細かなアクセス制限のいずれかで対応できる。サニタイジングが必須というわけではない。サニタイジングでカバーするという意味なら分かる。

以上を踏まえて、

以下  CSRF寄りの説明で補足します。

何が問題?

直接的な問題

大きくわけて2つありますが、主なところは JavaScriptが使えてしまうところ。もうひとつは悪意のある他人がただ訪れた人のブラウザ上の投稿(httpボディ)を自由にあつかえるということがポイント

もう少し具体的にJavaScriptの何が問題か?だから何?ってかんじですよね。

JavaScriptでできること、できないこと:不安になりすぎない

そもそもJSでできることをおさらいしましょう。JavaScript (js)や お亡くなりになりそうなJava Applet( :-| )は サンドボックス(影響が外に出ないように限定的)で動くしくみになっており、何でもかんでもできないようになってます。

できないこと

例えば、違うドメインの情報は取れなかったり(A)ローカルファイルなどのリソースに勝手にガンガンアクセスして情報を引き出すことはできません(B)。 (cookieなども同様)

   同じドメインのVPSがちょっと危ない(A)のが分かりますね。

できること

一方、URLを1回だけ他のドメインに投げつける(①)こともできますし、HTMLを書き換える(②)こともできます。 cookieも同じドメインであれば読む(③)ことができます。

具体的な被害は?

JavaScript

ローカルPCに電話やパスワードが書いてあっても、別に読み取られる心配はありません。よく文章で目的語や説明内容の範囲、そして主格もなくクレジットカードがバレる」と曖昧な表現が普通に使われて説明が終わっていますが、 勘違いの元だと思います。

また、他のサイト(銀行とか、決済のある Amazonとか FBとか Line)のクッキーやパスワードが読み取られることも基本ありません。 オートログインやiframeの組み合わせがグレーゾーンだが。。。後述

まず簡単な②のケースから。

②サイトを書き換えると、大したことないですが、書き換え=乗っ取りのイメージが普通の人やマスコミにあるようです。技術系の媒体にはちゃんと書いて欲しいですね。普通の人の中には、このサイトが乗っ取られたと勘違いして、クレジットカードなどの情報について漏れたかが不安になります(クラッカーとして技術的に一番簡単ですし、これで内部まで侵入されたわけでもありません)。またそのサイトの信頼が落ちます。  他の被害パターンは、デマをあたかもサイトの正式コメントのように書くことができます。

iframeを使って、一時的に他のサイト(有名で、被害を受ける今踏んだユーザがログイン中のままにしているもう一方の少し別の種類の脆弱性のサイト)で、クレジットカードの情報のページに遷移して情報やパスワードを読み取ります。しかしこれは、IE 8,9以外  chrome , firefox など最近のブラウザは制限がかかってiframeでは読み取れないようになっています。ちなみに、日本・韓国は世界的に見比べてもIEユーザが多い国となっています(2015年)。

まれかと思いますが、古いブラウザでは可能性として、別ウインドウで 画面にオーバーラップし  例えば銀行のログイン画面ぽいものを表示させる方法(フィッシング)もあります。ユーザが入力したらもちろんそのサイトの全権奪われてしまいます。

あとは、ウィンドウやダイアログを1000個以上立ち上げ操作不能にする過負荷を起こすサイトや、ActiveX経由で インストールさせるサイト。まちがってウィルスをインストールする(手動の確認ダイアログあり)とさらになんでもできるようになります。

①は②の派生系です。 同じサイトでもよいのですが、他のサイト(別ドメインや別のサービス)でも可能性があります。例えばユーザ本人のデータを削除する機能をWeb上で提供し、ログイン画面レスでそのページに getで遷移できてしまうと、ユーザの知らないところでデータが消えてしまいます(CSRFです)。

普通セッションはIPアドレスや時間をチェックして、同一ユーザらしさを確認しているので、他のPCからはアクセス出来ないのですがこの場合本人のPCからアクセスしているため、httpという仕組みでは区別がつきません。

 mixiで 「ぼくはまちちゃん」が大量に書き込まれたのは、受け側の方のサイトとしても脆弱性があったので、おそらく訪れた人がどんどん知らないうちに投稿した形になってたのだと思います。

③の場合、もし、 twitterのように 「remember me」 となっていて、ログインレスで入れる同じサイトであった場合、そのcookie情報で遷移でき、そのサイトで画面に表示させている情報(PWやクレジットカード、住所やコメント、画像など)にアクセスされてしまいます。他のサイトのJSでは直接読み取れませんが、連動技として、PCがウイルス感染していると、ブラウザの画面キャプチャをとられる可能性もあります。XSSというよりも、本質はすでに乗っ取られたことが問題です。

ちなみにiframeの他サイトへの脆弱性がいまだブラウザで残っているのであれば 他の有名ログインレスサイトではその情報も読むことができることになります。サーバ側ではどうしようもないですね。。。

ヘッダー書き換え

ほぼ、JSと同じですが、GETの後半が書き換えられることができると POSTリクエストなど要求リクエストを書き換え可能となる問題が起こります。つまり(悪意のあるユーザが予め設定した)好きなリクエストを投げつけることもできます。

GETに渡す文字数制限もある意味多少効果があるかもしれませんが、いまいちでしょう。

登場人物をおさらいして整理しておくと

・書き換え可能なサイト(a)
・GET処理を受け付けるサイト(b) 
・悪意のあるユーザ
・訪れたユーザ

(a)書き換え可能なサイト(ユーザが入力した情報が表示される)。掲示板や FBなどのイメージ。

そこに脆弱性があると問題が起こります。

それ以外の、(b)GET等で個別ユーザの処理を受け付ける別サイト。巻き添えを受ける側の脆弱性です。どうしようもないときもありますが。

悪意のあるユーザは  (a)のサイトのあるページにjsを仕込みます。

訪れた被害者となる人 も埋め込まれた後に (a)のサイトのあるページにおとずれます。

このように、脆弱性のあるサイトのタイプは2箇所あります。 (a)を踏む確率は低くなりますが有名なサイトではなく、悪意のあるサイトの場合に、ターゲットとなる(b)を狙うようなケースが CSRFです。

根本対処となる箇所は

つまり2つあります。 ひとつはユーザがデータを入力しそれをHTMLで表示するところ(a)。もうひとつは Getデータでユーザの処理をするところ(b)です。

ユーザの入力に対して

対応するのではありません。

HTMLとして ブラウザ(クライアント)に返すときに処理します。

ユーザの情報で、ユーザがそのサイトから入力しないデータもありえますので、どちらにしろ出力時に処理が必要になります。また、入力と出力の2回対応すると、おかしなデータになるためコントロール制御が難しくなります。入力時はサーバとしての入力チェック(内部がおかしくならない程度)だけ行います。

DBにアクセスされたり、shellや eval()で実行される脆弱性はまた別の話です。

出力するときに、例のサニタイジングで JavaScriptやタグを無害化します。

忘れがちなところとして、未だにWebで起こっている問題箇所が DOM-XSSです。そちらは別途紹介します。

 

こうすればよいですがまだ足りないところがあります。それは httpヘッダー部分です。実はGETで返してしまうと、GETはhttpヘッダー部分ですので、 httpボディ部分に影響をおよぼすことが可能となります。具体的には前側にヘッダーがあり、後半にボディがあるのですが、その境目は空行(改行ふたつ)がマークとなっています。つまり、GETのなかで空行を入れてしまうと、それ以降ボディとブラウザに認識され、ボディ書き換えの問題が起こります。

ユーザの入力は GETに置かないような設計が必要になります。そうすればボディ部分が任意に書き換えられることはありません。

railsなどでは、"隠しtoken"を入れたり、あとは不自然な画面遷移(ダイレクトなページ遷移による書き換えやIPが急に変わったりするケース)を弾いたりします。 その対策はどちらかというと 悪意のあるユーザが他のユーザの表示を変更することに対するXSS対策というよりも、他のユーザが勝手にユーザ情報を変更出来てしまうことに対する(サイト登録・変更時などの)脆弱性対策だと思います。

ただFORMなどのボディパラメータをチェックしてその影響を受けないようにする対処は、乗っ取られないようにサニタイジング(コマンド処理やOS、DB操作処理を消すために、HTMLやコマンドの文字列化対応:&ltとかBASE64エンコーディングなど)もするので、本質から少しずれている対処ですが、XSSにも有効に機能します。

GETで入力チェックするところについて

サニタイジングが不十分な他のサイトから、一般の被害者が飛んできたケースです。なにせこれはユーザ本人のログインと区別がつかないので、オートログインしていた場合サイト側として入れざるを得ません。

これは、いくつか対応がありますが、変更(登録、削除、表示も含む)するときは、GETで受け付けないことが肝心です。またyahooで重要な変更をする時は、再度パスワード入力が求められるのはその対応策です。

それとGETでストレートにユーザの情報ページに行かないようにするのも大事です。最近ではPWやクレジットカードが表示されてないサイトも増えてきているのはその対策のためです。

クロスドメインのブラウザの脆弱性が原因なので、これは古いブラウザがなくなるように祈るか、古いブラウザのアクセスはシャットダウンするほうがいいかもしれません。

銀行はワンタイムパスワードにより、もっと広い範囲でPW流出対応をしていますね。結果、他サーバから書き換えさせないためのこのXSS対策にもなります。

FBなどでコメントのページでも毎回PW入力を求めると、ユーザビリティが下がりすぎるので、Webアプリケーション側ではこれ以上対応できません。タイムアウトを短くすることで可能性を下げることはできます。あとはユーザが定期度にログアウトする(ログインしっぱなしにしない)ことが求められます。

結構この対策を考えてみました。機械に読めないようにするとか、オートログイン時はツークッション以上のユーザアクションにするとか、URLをランダムにするとか考えました。いずれもたいして効果的でない上に、ユーザビリティがかなり落ちてしまいます。

補足:クッキーがバレてしまったとき用

出力時の対策がされていたらこのページの観点では必要ないですが、他のサイトから、クッキー情報だけでそのままログインさせないようにすることも賢明です。例えば、銀行などでは、PCやIP、ブラウザが変わると自動ログインさせず、必ず再ログインさせます。(つまり、IPアドレスなど送信元もチェックして脆弱性対策をすることで、XSS対策を含んでいることにもなる)

補足:フィッシング

フィッシングの対応については、サーバ側はあまり対応できません。ユーザがPWを入力するときに、自分からサイトを開いた時以外は入力しないこと、サイトのhttpsや証明書を確認すること、URLを確認することも大事です。(ただ hostを書き換えられているとIT技術者でもかなり、気づくのが難しい・面倒です)。

また、メールがトリガーになっていることが多いと思います。

サーバ側としては、ログインシール(ユーザが独自に設定したアイコンを表示させる。ロジックはログイン前なのでややこしいい)やビジュアルログイン(ジェスチャー等)、生体認証、その他にログイン毎(奪われた後の正式ページで)にメールやSMSでの通知などでカバーすることになります。

まとめ

HTML出力時の対策が根本対処となりますが、 他の脆弱性サイトから自サイトへ連動され、被害者のサイトとならないように、セッションがあっても自由にユーザに操作させない・表示しないような対策も必要だということがわかりました。

formの Tokenや入力時チェックはXSSの本質的な対策ではありません("クロス"ではなくサイト単体のそれ以前の問題ですし、HTML出力時に対処できていればXSSの方の問題はありません。またログインや更新チェックについても、他ユーザにログインさせないという別の目的をしっかり対策しておくのが前提です。他のユーザが更新出来てしまえば、XSSよりも悪質ですね)

また、ユーザ側として使う側の対応(重要なサイトでのログアウト、ログイン情報の入力時の注意(フィッシング)など)も重要な事がわかりました。

補足:最近の動向

最近はクロスプラットフォーム開発や、 クライアントサイドでの高機能なjsがあるため、そちらについても対策が求められています。DOM-based-XSSについてはこちら

おまけ

Cookieの盗聴について

Javaのセッションなどからは、他のPCから取得してもネットワークのセッションを確立できないと思う(概念的なロジカルは想像できるが、具体的なロジックまでは情報を入手できていないが)

それでも追加で 2重に対策したいのであれば、以下のような簡単にできるやり方がある。

通信経路で流さない設定:Secure属性

セッションハイジャックなど、通信経路(ブラウザからサーバ間。ただ、運用者間からサーバは除く)クッキー情報を盗聴されないようにするには、Cookie にSecure属性 を付ける。 https通信以外ではその 設定されたCookie情報はブラウザから送信されない。Javaでも簡単にできるし、実際にも1行http上に追加するだけ。Tomcatの設定でもできる。

経路上でクッキーを読み取られ、ログインされることはまず起こらない(httpsのプロトコル  TLS 1.2が破れない限り)。他サイトどころかそのサイトのクレカ情報も直接アカウントをとられることはなくなり漏れにくくなる。

ただ最近は、クレカ情報はサーバ上で保持してはいけない流れに欧州、日本(PCIDSS: 2018年3月まで必須。ECサイトも含まれるため、中規模ぐらいのショッピングサイトなどは代行に外注するなどだろう)ではなっている。

残りの対策は、ブラウザやローカルPC側と、サーバに直接アクセスできる運用者やインフラ管理者(クラウド提供者など)の部分となる。

JavaScriptで取得できない設定:HttpOnly属性

上記と同様に HttpOnly属性を Cookieにつけて、JavaScriptからブラウザ上読み取られないようにすることができる。多少設計上不自由なケースもあるかもしれないが、そのため、XSSでCookie読み込みJSが埋め込まれても、悪意のあるコードに読まれる可能性がなくなる。

 

Delicious にシェア
Digg にシェア
reddit にシェア
LinkedIn にシェア
LINEで送る
email this
Pocket




コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です