XSS

エックスエスエス

XSS を分かりやすく

「XSS(クロスサイトスクリプティング)」って聞いたことありますよね。ここではその「XSS」についてフランクに解説します。

まず、XSSとは何か。これは、ウェブサイトに悪意のあるスクリプトが埋め込まれて、訪問者のブラウザ上で実行されてしまう攻撃方法のことを指すんですね。つまり、いわゆるセキュリティ上の問題なんです。

このXSSを分かりやすく説明するために、一つ例え話を思い浮かべてみましょう。

「あなたがオーナーのレストラン」を想像してみてください。レストランは評判が命ですよね。評判が良ければお客さんが増え、ビジネスは好調に推移します。その評判を上げるために、「お客さんの声」を取り入れ、その声を公開するボードを設置しました。

ここで、一人の悪意のあるお客さん(ハッカー)が来店し、「お客さんの声」に偽の情報や誤解を招くメッセージを書き込みました。他のお客さんがそのメッセージを見てしまうと、お店の評判が下がったり、最悪の場合、お客さんがその偽の情報に基づいて行動し、自分自身に問題が生じるかもしれません。

これがXSSの概念に似ています。ユーザーがウェブサイトに情報を投稿することが許されている場合、ハッカーはその投稿欄に悪意のあるスクリプトを埋め込み、そのウェブサイトを訪れた他のユーザーのブラウザ上でそのスクリプトが実行されてしまうんです。

つまり、XSSは「他のお客さん(ユーザー)を守るために、どうやって偽のメッセージ(悪意のあるスクリプト)をフィルターにかけ、ブロックするか」について考える問題なんですね。これが「そもそもこれ使う意味あるん?」って思われる方への答えです。ここまで大丈夫ですか?

結論

XSS(Cross Site Scripting)とは、ウェブアプリケーションのセキュリティ上の脆弱性の一つで、不正なスクリプトを注入されて実行される攻撃手法を指します。攻撃者は、ウェブページに不正なスクリプトを埋め込むことで、そのページを訪れた他のユーザーのブラウザ上でスクリプトを実行します。これにより、ユーザーの情報(クッキーなど)が攻撃者に盗まれるなどの被害が発生します。

XSS の歴史的変遷

XSS の脆弱性は、ウェブの初期から存在していました。当初は、ウェブページが静的だったため、XSSの脆弱性はそれほど深刻な問題ではありませんでした。しかし、ウェブが進化し、ウェブアプリケーションが一般的になるとともに、XSS の脆弱性は大きな問題となりました。

その後、ウェブブラウザのセキュリティ対策が進化し、標準でXSS対策が導入されるようになりました。しかし、完全に排除することは難しく、今日でも新たなXSSの脆弱性が発見されることがあります。

XSS と Jamstack の関係

Jamstack とは JavaScript、API、Markup の頭文字を取った言葉で、静的サイトジェネレーターを用いた開発手法を指します。Jamstack では、全てのページがビルド時に HTML として生成されるため、実行時に動的に HTML を生成する従来のサーバーサイドレンダリングと比べて、XSS のリスクが低いと言えます。

しかし、Jamstack でも JavaScript で動的な処理を行う部分においては XSS のリスクが存在します。例えば、API から取得したデータをそのまま描画する場合などは、そのデータに不正なスクリプトが含まれている可能性があります。

XSS を使うメリット

ユーザー情報の保護

XSS を理解し、適切な対策を行うことで、ユーザーの情報を攻撃者から守ることができます。

ウェブアプリケーションの信頼性の向上

XSS の脆弱性を排除することで、ウェブアプリケーションの信頼性を向上させることができます。

法的な問題の回避

ユーザーの情報が盗まれたり、ウェブサイトが攻撃に利用されたりすると、法的な問題を引き起こす可能性があります。XSS の対策を行うことで、これらのリスクを回避することができます。

XSS を実装

XSS を防ぐための一般的な対策としては、ユーザーからの入力をそのまま出力しない、あるいは出力する場合でも適切にエスケープすることがあります。

例えば、Next.js と TypeScript を使ってユーザーからの入力を受け取り、その入力を表示する簡単なコンポーネントを考えてみましょう。

type Props = {
  userInput: string
}

const DisplayUserInput = ({ userInput }: Props) => {
  return <div>{userInput}</div>
}

このコードでは、ユーザーからの入力をそのまま出力しています。このため、ユーザーが <script> タグを含む入力を行うと、そのスクリプトが実行されてしまいます。

これを防ぐには、ユーザーからの入力をエスケープする必要があります。React では、通常、 JSX 内に {} を使って値を埋め込むと、その値は自動的にエスケープされます。しかし、dangerouslySetInnerHTML などを使って HTML を直接出力する場合は、自動的なエスケープは行われないため、注意が必要です。