iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

セキュリティ月間から7ヶ月程経ったので改めてセキュリティについて考えてみた

はじめに

こんにちは!株式会社iimonでフロントエンジニアをしているあめくです!
今回は「サイバーセキュリティ月間」から約7ヶ月が経ち、意識が薄れがちなこのタイミングで、改めてセキュリティの重要性を考えてみたいと思います。
そもそも「サイバーセキュリティ月間」とは、政府がサイバーセキュリティに関する普及啓発を目的に、毎年 2月1日〜3月18日 を定めている期間です。
この期間中でもよく話題に上がるのが、セキュリティの基本中の基本である 情報セキュリティの3要素(CIA) です。

なぜセキュリティ対策を行うのか

セキュリティ対策を行う主な理由は、情報資産を不正アクセス、情報漏洩、改ざんといった様々な脅威から守り、その機密性・完全性・可用性を維持することにあります。

  • 機密性 (Confidentiality): 許可された者だけが情報にアクセスできること。
    • 例: 顧客の個人情報、企業の機密データなどが、外部に漏洩しないようにする。
  • 完全性 (Integrity): 情報が正確で、改ざんや破壊が行われていないこと。
    • 例: ウェブサイトのコンテンツが不正に変更されないようにする。
  • 可用性 (Availability): 許可された者が、いつでも情報やシステムを利用できること。
    • 例: DDoS攻撃などによってサービスが停止しないようにする。

これらの要素を脅かすリスクに対処するため、セキュリティ対策は不可欠です。

どのような攻撃手法があるのか

今回は Webアプリケーションにおける代表的な4つの攻撃手法について説明します。
これらは一見するとサーバー側の問題に見えることが多いですが、実際にはフロントエンド実装とも密接に関わっています。たとえば、ユーザー入力の反映処理、フォーム送信の扱い、クリックイベントの処理など、日常的なコードがセキュリティリスクに直結するケースも少なくありません。

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

XSS(クロスサイトスクリプティング)とは、Webアプリケーション内の脆弱性を利用して、悪意のあるスクリプトをユーザーのブラウザ上で実行させる攻撃手法です。
攻撃者は、ウェブサイトの入力フォームなどに不正なスクリプトを埋め込み、それを閲覧した他のユーザーのブラウザ上で実行させることで、セッション情報を盗み取ったりサイトの改ざんなどを行います。

XSSクロスサイトスクリプティング)は、攻撃手法によって大きく分けて3つのパターンに分類されます。

1 Stored XSS(格納型XSS/蓄積型XSS

攻撃者が悪意のあるスクリプトをWebアプリケーションのデータベースやファイルに保存し、ユーザーがその保存されたデータにアクセスしたときに実行されるパターンです。
不正なスクリプトを含むデータがデータベースなどに蓄積されることから「格納型XSS」や「蓄積型XSS」と呼ばれています。

特徴: 攻撃が永続的に残り、不特定多数のユーザーに影響を与える可能性が高い。

例: 掲示板やSNSのプロフィール欄にスクリプトが書き込まれるケース。

対策: サーバー側で、データベースに保存する前に、入力値を適切にエスケープ処理(無害化)すること。また、表示する際にも改めてエスケープ処理を適用し、二重の防御を徹底します。

2 Reflected XSS(反射型XSS

攻撃者が悪意のあるスクリプトをURLのパラメータに含めてユーザーに送信し、ユーザーがそのURLにアクセスすると、サーバーがそのスクリプトを反射(リフレクト)して返してしまうパターンです。

特徴: 攻撃が一時的で、URLを開いた特定のユーザーにのみ影響を与える。

例: 検索フォームの入力値がURLにそのまま表示され、そこにスクリプトが埋め込まれるケース。

対策: URLのクエリパラメータなど、ユーザーからの入力を受け取ったデータをそのままHTMLに出力せず、必ずエスケープ処理を適用すること。これにより、スクリプトがブラウザ上で実行されるのを防ぎます。

3 DOM-based XSS(DOMベースXSS

悪意のあるスクリプトがサーバーを経由せず、ユーザーのWebブラウザ上でDOM(Document Object Model)を操作することで実行されるパターンです。

特徴: サーバー側の処理に問題がなくても発生しうる。

例: JavaScriptがURLのフラグメント(#以降)を読み取り、その値を使ってDOMを動的に書き換える際に、スクリプトが挿入されるケース。

対策: クライアントサイドのJavaScriptコードで、URLのフラグメントなど信頼できないデータソースから取得した値を、安易にDOMに直接書き込まないこと。代わりに、textContentinnerTextプロパティを使用するなど、安全なAPIを利用します。

これらの3つのパターンは、スクリプトがどこに保存され、どのように実行されるかという点で異なりますが、いずれもユーザーのブラウザ上で悪意のあるスクリプトを実行させるという点で共通しています。

参考: 安全なウェブサイトの作り方 - 1.5 クロスサイト・スクリプティング

XSSの比較
種類 データの保存 攻撃の持続性 典型的な経路
Stored XSS データベースに保存 持続的 コメント、投稿
Reflected XSS 保存されない 一時的 URL、フォーム
DOM-based XSS 保存されない 一時的 JavaScript処理

ではここで問題です!下記はReactの処理ですがこの処理に脆弱性はあるでしょうか?

import React, { useState } from "react";

const XSSDemo: React.FC = () => {
  const [input, setInput] = useState("");

  return (
    <div>
      <h2>DOM-based XSS デモ</h2>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="HTMLを入力してください"
        style={{ width: "100%", marginBottom: 10 }}
      />
      <div
        style={{ border: "1px solid gray", padding: 10 }}
        dangerouslySetInnerHTML={{ __html: input }}
      />
    </div>
  );
};

export default XSSDemo;

回答: 下記の箇所にXSS脆弱性があります!

      <div
        style={{ border: "1px solid gray", padding: 10 }}
        dangerouslySetInnerHTML={{ __html: input }}  // ここの処理!
      />

Reactは優秀なXSS防御機能(自動的にエスケープしてくれます)を持っていますが、dangerouslySetInnerHTMLはその保護を意図的に回避するため使用時は細心の注意が必要です。
名前の通り「危険」であり、本番環境では避けるべきです。
解決策としては下記のように input をそのまま出力するかサニタイズする必要があります。

<div>{input}</div>

or

import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ 
  __html: DOMPurify.sanitize(input) 
}} />

CSRF(クロスサイト・リクエストフォージェリ)

CSRF(クロスサイトリクエストフォージェリ)とは、ユーザーが意図しない操作をWebアプリケーションに行わせる攻撃手法です。攻撃者は、偽のページやメールを用意し、ユーザーにアクセスさせます。その結果、ログイン済みのユーザーのセッションを利用して、本人の知らないうちに不正な操作(例: パスワード変更、商品の購入、SNSへの投稿など)が実行されます。

特徴: ユーザーがログイン中であることを前提に攻撃が成立する。攻撃はワンクリックやページ読み込みで成立し、被害者は気づきにくい。

例: SNSの投稿フォームを悪用し、本人のアカウントで勝手に投稿させるケース。

対策: CSRFトークンを発行し、重要なリクエストに含めて検証する。Cookie に SameSite 属性 を設定し、外部サイトからの送信を制限する。などなど...

参考: 安全なウェブサイトの作り方 - 1.6 CSRF(クロスサイト・リクエスト・フォージェリ)

クリックジャッキング

クリックジャッキングは、ユーザーに意図しないボタンやリンクをクリックさせる攻撃手法です。攻撃者は、透明なレイヤーや見えない要素を正規のWebサイトのページの上に重ね合わせます。ユーザーは、目の前の正規のページを操作しているつもりでクリックしますが、実際にはその下にある見えないレイヤーの不正な要素をクリックしてしまいます。

特徴: ユーザーの視覚を欺き、操作を乗っ取る。

例: 「無料ギフト」と表示されたボタンをユーザーがクリックすると、実際にはその下にある「銀行振込」ボタンがクリックされてしまうケース。

対策: X-Frame-Options ヘッダ や Content-Security-Policy (frame-ancestors) を設定して、他サイトで自分のページが iframe に埋め込まれないようにする。などなど...

参考: 安全なウェブサイトの作り方 - 1.9 クリックジャッキング

オープンリダイレクト

オープンリダイレクトは、ウェブサイトが外部サイトへのリダイレクト(転送)機能を悪用する攻撃手法です。正規のウェブサイトのドメインを持つURLに、攻撃者が指定した不正なURLをパラメータとして挿入します。ユーザーはそのURLが正規のものだと信じてクリックしますが、実際には悪意のあるサイトに転送されてしまいます。

特徴: 信頼できるサイトのURLを利用するため、ユーザーが騙されやすい。

例: https://example.com/redirect?url=https://phishing-site.com のようなURLをクリックすると、example.comを経由してフィッシングサイトに転送されてしまうケース。

対策: リダイレクト先を ホワイトリスト方式 で制御し、外部URLを直接指定できないようにする。外部URLに遷移する場合は、警告ページを挟む。などなど...

まとめ

  • 今回はフロントエンドでよく目にするセキュリティの内容に触れてみましたが、フロントだけで完結する防御策は少ないけど、フロントエンドエンジニアが「ここ危ない」と気づけることが大切だなと感じました。
  • 例えば「ReactでdangerouslySetInnerHTMLを使うと危険」「フォーム送信にはCSRF対策が必要」「クリックジャッキングはHTTPヘッダ設定で防げる」といった具合に、現場で注意すべき観点を持つことが重要です。
  • また、IPAから毎年発表される情報セキュリティの資料も参考になります。セキュリティ対策はソフトウェアだけでなく、私たちのプライベートな行動や意識にも関わってきます。
  • セキュリティは「一度学んだら終わり」ではなく、技術の進化や攻撃手法の変化に合わせて考え続ける必要があります。この記事が少しでも日々の開発や学びのきっかけになれば嬉しいです!

最後に

現在弊社ではエンジニアを募集しています!

この記事を読んで少しでも興味を持ってくださった方は、ぜひカジュアル面談でお話ししましょう!

iimon採用サイト / Wantedly / Green

最後まで読んでいただきありがとうございました!

参考

フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識 IPA情報処理推進機構 安全なウェブサイトの作り方