フロントエンドへの代表的なセキュリティ対策とその実践例(1)

// Security

// Part of フロントエンドへの代表的なセキュリティ対策とその実践例

はじめに

ウェブサイトやアプリケーションのセキュリティ対策では、フロントエンドとバックエンドと両方における対策が重要になります。ですが今回は、フロントエンド側の対策、特にクロスサイトスクリプティングの具体的な例とそれに対抗するためのセキュリティ対策について解説と実践例を挙げていきたいと思います。

クロスサイトスクリプティング(XSS)対策

クロスサイトスクリプティングとは

クロスサイトスクリプティング(XSS)とは、何らかの形で悪意のあるスクリプトを挿入することで、セッショントークンやCookieを盗んだりするセキュリティ攻撃です。

クロスサイトスクリプティングが起こる例とその対策

クロスサイトスクリプティングは、主にユーザーが入力した内容を適切に処理しないまま実行する際に起こりえます。 フォームなどにユーザーが入力したテキストを、エスケープ処理をせずにHTMLに直接表示する、などの例が挙げられます。 その結果、ユーザーのセッショントークンやCookieを盗まれて、個人情報やアカウント情報が盗まれる、セッション情報を悪用されるなどの被害が起こる可能性があります。

実践例

今回はユーザーが入力したテキストを画面に表示する実装を例に挙げます。 下記の例では、ユーザーが入力したテキストにエスケープ処理を施すことで、悪意のあるスクリプトの実行を防いでいます。

<!DOCTYPE html>
<html>
<head>
  <title>XSS test</title>
</head>
<body>
  <h1>コメントを入力してください</h1>
  <form id="commentForm">
    <label for="comment">入力欄</label>
    <input id="comment" type="text" name="text" placeholder="コメントを入力してください。">
    <button type="submit">送信する</button>
  </form>
  <p>入力されたコメント</p>
  <div id="output"></div>

  <script>
    document.getElementById("commentForm").addEventListener("submit", (e) => {
      e.preventDefault();

      function escapeHTML(str) {
        return str.replace(/&/g, '&amp;')
                  .replace(/</g, '&lt;')
                  .replace(/>/g, '&gt;')
                  .replace(/"/g, '&quot;')
                  .replace(/'/g, '&#039;');
      }

      const comment = document.getElementById("comment").value;
      const escapeComment = escapeHTML(comment);
      document.getElementById("output").innerHTML = escapeComment;
    })
  </script>
</body>
</html>

エスケープ処理を行わなかった場合

エスケープ処理を行わない場合には、有効な script タグが挿入されてしまうため、悪意のあるスクリプトが実行されてしまいます。

実装例

ユーザーが入力したテキストをそのままHTMLに挿入する実装になってしまっています。

<script>
    document.getElementById("commentForm").addEventListener("submit", (e) => {
      e.preventDefault();

      const comment = document.getElementById("comment").value;
      document.getElementById("output").innerHTML = comment;
    })
  </script>

結果

スクリプトタグが有効になり、悪意のあるスクリプトが実行されてしまいます。

<div id="output">
	<script>悪意のあるスクリプト</script>
</div>
エスケープ処理を行った場合

エスケープ処理を行う事で、<>や/などが安全な文字列として変換されるため、悪意のあるスクリプトは実行されません。

実装例

ユーザーが入力したテキストの内、危険な文字をエスケープ処理しています。

<script>
    document.getElementById("commentForm").addEventListener("submit", (e) => {
      e.preventDefault();

      function escapeHTML(str) {
        return str.replace(/&/g, '&amp;')
                  .replace(/</g, '&lt;')
                  .replace(/>/g, '&gt;')
                  .replace(/"/g, '&quot;')
                  .replace(/'/g, '&#039;');
      }

      const comment = document.getElementById("comment").value;
      const escapeComment = escapeHTML(comment);
      document.getElementById("output").innerHTML = escapeComment;
    })
  </script>

結果

エスケープ処理の結果、スクリプトタグは無効になっています。

<div id="output">&lt;script&gt;悪意のあるスクリプト&lt;script&gt;</div>
.textContent を使用する場合

.innerHTML を使用する代わりに .textContent を使用することで、入力されたテキストはただの文字列として扱われます。

実装例

<script>
    document.getElementById("commentForm").addEventListener("submit", (e) => {
      e.preventDefault();

      const comment = document.getElementById("comment").value;
      document.getElementById("output").textContent= comment;
    })
  </script>

結果

入力されたテキストがただの文字列として扱われ、スクリプトタグは無効になっています。

<div id="output">&lt;script&gt;悪意のあるスクリプト&lt;script&gt;</div>

まとめ

クロスサイトスクリプティングは、代表的なセキュリティリスクであり、適切な対策が無ければユーザーのデータが危険にさらされる可能性があります。ですが、フロンエンド側において今回紹介したようなエスケープ処理や.textContentを利用するなどの適切なセキュリティ対策を行うことで、そのリスクを低減することができます。