AUTOMATION NOTE — 136

Google Forms×BigQuery 不正検知の設計ガイド

Google Workspace の BigQuery Export 機能は監査ログを継続エクスポートできる一方、Google Forms の回答内容は対応サービスに含まれていません(2026年6月時点、公式ヘルプ確認済み)。この記事では、Forms の回答データを BigQuery に取り込む設計経路を整理し、不正回答・異常パターンを SQL で検知するフレームワークを解説します。

この記事を読んだほうが良い人

  • IT資産申請・入退社対応・社内アンケートに Google Forms を活用している情シス担当者
  • フォーム回答データのセキュリティ監視体制を整えたいと考えている方
  • Google Workspace Enterprise Standard 以上を利用している、またはBigQuery連携を検討中の方
  • BigQuery の基本的な SQL は書けるが、Forms との組み合わせ方法がわからない方

Googleフォームがセキュリティの死角になりやすい構造的な理由

情シスが Google Forms をセキュリティリスクと認識しにくい理由は、「作れる・使える・答えられる」というハードルの低さにあります。IT資産申請、入退社手続き、セキュリティ教育の確認テストなど、フォームが業務に溶け込むほど、回答データの扱いへの注意が薄れがちです。

フォームは表側の作りやすさと、裏側の回答データ管理がアンバランスになりやすいツールです。構造的な問題として特に注意したいのが次の3点です。

まず、フォームの共有設定がデフォルトのまま運用されやすい点です。Google Forms は作成者が自由に「リンクを知っている全員」への公開設定を選べます。社内アンケートのつもりで作ったフォームに、リンクが転送されて意図しない外部回答が届いても、管理コンソール側では即時に気付けません。

次に、回答データが接続されたスプレッドシートに蓄積される点です。スプレッドシートへのアクセス権が「編集者を追加してしまっている」「共有リンクで誰でも閲覧できる」状態になっていても、フォームの設計者が定期的に確認していないケースは珍しくありません。

さらに、管理コンソールからフォームの利用状況を一覧できない点もあります。Drive ファイルとして存在するため個別のファイル操作ログは残りますが、「組織内にいくつのフォームが存在し、それぞれの共有設定がどうなっているか」をまとめて可視化するネイティブな機能は現時点で限られています。

このような構造的な問題が積み重なった結果、以下のようなリスクが実在します。

  • IT資産申請フォームで同一人物が複数回答し、許可枠を超えた申請を通そうとする
  • 入退社手続きフォームに個人番号やパスワードが誤入力される
  • 外部に公開したアンケートにボット的な一括回答が届く
  • 深夜・休日に不自然なタイミングで回答が集中する
  • 機密性の高い社内申請情報が、フォーム作成者の退職後もスプレッドシートにアクセス可能な状態で残る

管理者が定期的に CSV をダウンロードして目視確認するだけでは見逃しやすく、件数が増えるほど手作業の限界が出ます。こうした課題に対して、BigQuery を使った統計的・継続的な監視設計を整えておくことが有効です。

Google Forms BigQuery 不正検知の設計フレームワーク

設計の核心は「検知したいシナリオ → 必要なデータ → 検知ロジック」の順番を守ることです。「とりあえずBigQueryに流してから考える」という進め方は、データが増えたときにSQLが煩雑になる原因になります。

Googleフォームの異常検知:シナリオと検知アプローチの対応表

まず監視したいリスクを分類します。下の表はシナリオ・必要データ・検知アプローチの対応を整理したものです。

脅威シナリオ 必要なデータ 検知アプローチ
同一人物の重複申請 回答者メール × 送信時刻 GROUP BY + HAVING で重複カウント
短時間の集中投稿(ボット疑い) タイムスタンプ分布 時間ウィンドウ集計
業務時間外の回答集中 送信時刻 × 時間帯 EXTRACT(HOUR) でフィルタリング
機密キーワードの誤入力 フリーテキスト回答 正規表現によるパターンマッチ

Forms データを BigQuery に取り込む2つの経路

経路A:GWS の BigQuery Export(Drive 監査ログ経由)

管理コンソールのレポート設定から BigQuery Export を有効にすると、Drive 監査ログが BigQuery にエクスポートされます。Drive 監査ログには Google Forms ファイルの作成・閲覧・応答ファイルへのアクセスなどが含まれます。

ただし、フォームの回答内容そのものはこの経路には含まれません。公式ヘルプの対応サービス一覧(Accounts / Admin / Calendar / Chrome / Drive / Gmail / Chat / Login / OAuth など)に Google Forms は記載がなく、Drive 監査ログ内のフォームファイル操作履歴として間接的に取得できる形にとどまります。「誰がいつフォームファイルを操作・共有したか」というメタ監視に向いています。

この機能を利用するには Frontline Standard/Plus・Enterprise Standard/Plus・Education Standard/Plus・Enterprise Essentials Plus のいずれかが必要です。

経路B:Forms 回答データを直接 BigQuery に転送(GAS パイプライン)

GAS(Google Apps Script)のフォーム送信トリガーを使い、回答が届くたびに BigQuery にレコードを逐次インサートする構成です。GAS スクリプトで定期的に差分インサートする構成、または BigQuery 外部テーブルとしてシートをリンクする方法もあります。リアルタイム検知が必要な用途では GAS トリガーが現実的です。

回答内容(テキスト・選択肢)を直接 BigQuery で分析できるため、不正回答検知の主力はこちらになります。

以下は2つの経路の比較まとめです。

判断基準 経路A(BigQuery Export) 経路B(GAS パイプライン)
検知対象 ファイル操作・アクセス 回答内容・回答者の行動
リアルタイム性 数分〜10分程度 GAS トリガーで即時
必要エディション Enterprise Standard 以上 GAS が使えるプランなら可
実装コスト 設定のみ GAS コーディングが必要

GAS パイプラインの基本設計

経路B を選んだ場合、GAS スクリプトの基本構造は次のようになります。フォームの送信イベントをトリガーとして、回答内容を整形して BigQuery にインサートする流れです。

以下は GAS の実装イメージです。YOUR_PROJECT_IDYOUR_DATASET_IDforms_responses は実際の環境に合わせて書き換えてください。

// フォーム送信時に実行するトリガー関数
function onFormSubmit(e) {
  const response = e.response;
  const itemResponses = response.getItemResponses();

  const row = {
    respondent_email: response.getRespondentEmail() || '',
    submitted_at: response.getTimestamp().toISOString(),
    form_id: e.source.getId(),
    // 回答内容を JSON 文字列として格納
    answers_json: JSON.stringify(
      itemResponses.map(r => ({
        question: r.getItem().getTitle(),
        answer: r.getResponse()
      }))
    )
  };

  insertToBigQuery(row);
}

function insertToBigQuery(row) {
  const projectId = 'YOUR_PROJECT_ID';
  const datasetId = 'YOUR_DATASET_ID';
  const tableId = 'forms_responses';

  BigQuery.Tabledata.insertAll(
    { rows: [{ insertId: Utilities.getUuid(), json: row }] },
    projectId,
    datasetId,
    tableId
  );
}

このスクリプトは GAS エディタの「トリガー」設定からフォームの「回答送信時」イベントに紐付けます。respondent_email が取得できるのは、フォームの設定で回答者のメールアドレス収集が有効な場合のみです。また、BigQuery API の高度なサービスを GAS の [サービス] から有効化しておく必要があります。

スキーマは最初からすべてのフィールドを分解するよりも、answers_json として JSON 文字列で保持し、BigQuery 側で JSON_VALUE / JSON_QUERY 関数で必要な時だけ展開する設計の方が、フォームの設問変更に柔軟に対応できます。設問が変わるたびにテーブルのスキーマ変更が発生する構成は、運用コストが予想以上に高くなります。

SQLで設計するGoogleフォームの不正回答検知パターン

以下の SQL は、経路B(GAS パイプライン)で構築した forms_responses テーブルを対象にしています。フィールド名は実際のスキーマに合わせて調整してください。

検知1:同一メールアドレスによる重複回答

特定のフォームで同じメールアドレスが複数回回答しているケースを検出します。IT資産申請や承認フローに使用しているフォームで特に有効です。このクエリの結果を週次でスプレッドシートに書き出す運用にしておくと、担当者が定期確認しやすくなります。

-- forms_responses テーブルの想定フィールド:
--   respondent_email: 回答者のメールアドレス
--   submitted_at: 送信日時 (TIMESTAMP)
--   form_id: フォームID

SELECT
  respondent_email,
  form_id,
  COUNT(*) AS response_count,
  MIN(submitted_at) AS first_response,
  MAX(submitted_at) AS last_response
FROM `your_project.dataset.forms_responses`
WHERE DATE(submitted_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND respondent_email IS NOT NULL
GROUP BY respondent_email, form_id
HAVING COUNT(*) >= 2
ORDER BY response_count DESC;

HAVING COUNT(*) >= 2 の閾値は、フォームの性質によって調整します。再申請が制度上許容されているフォームであれば >= 3 などに緩めるか、対象フォームを絞り込む条件を追加するのが現実的です。

検知2:短時間での集中投稿(ボット的行動の疑い)

1時間あたり10件を超える回答が発生した時間帯を抽出します。外部公開フォームや、通常の業務では想定できないペースの回答を検知できます。閾値(ここでは10)は組織の通常回答ペースに合わせて調整します。

SELECT
  form_id,
  TIMESTAMP_TRUNC(submitted_at, HOUR) AS hour_bucket,
  COUNT(*) AS response_count
FROM `your_project.dataset.forms_responses`
WHERE DATE(submitted_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY form_id, hour_bucket
HAVING COUNT(*) >= 10
ORDER BY response_count DESC;

このクエリは特に外部公開のアンケートフォームに対して有効です。セキュリティ教育の確認テストなど、受講者数が決まっているフォームであれば、「想定受講者数を大きく超えた件数が1時間以内に届いた」ことを検知するための基準値を設定しやすくなります。

検知3:業務時間外の回答

タイムゾーンを日本時間(Asia/Tokyo)に変換し、9〜17時以外の回答を抽出します。セキュリティ教育アンケートなど「業務中に回答することが前提」のフォームで有効です。深夜の大量回答はボットや不正スクリプトの可能性があり、単体では証拠になりませんが、検知2の結果と組み合わせると判断根拠が強まります。

SELECT
  respondent_email,
  form_id,
  submitted_at,
  EXTRACT(HOUR FROM DATETIME(submitted_at, 'Asia/Tokyo')) AS submission_hour
FROM `your_project.dataset.forms_responses`
WHERE DATE(submitted_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND EXTRACT(HOUR FROM DATETIME(submitted_at, 'Asia/Tokyo')) NOT BETWEEN 9 AND 17
ORDER BY submitted_at DESC;

検知4:フリーテキストへのキーワード混入

記述式の回答欄を持つフォームで、個人番号のような数値列パターンやパスワードっぽい表現が混入していないか確認します。フォームの誤入力による情報漏えいリスクを早期に発見できます。正規表現パターンは組織のポリシーに合わせて追加・調整してください。

SELECT
  respondent_email,
  submitted_at,
  -- JSON文字列全体マッチのため誤検知あり。精度向上には JSON_VALUE での展開が推奨
  answers_json
FROM `your_project.dataset.forms_responses`
WHERE DATE(submitted_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND REGEXP_CONTAINS(
    answers_json,  -- JSON全体マッチのため誤検知あり。精度向上には JSON_VALUE での展開が推奨
    r'\d{12}|マイナンバー|password\s*[:=]\s*\S+|パスワード\s*[::]\s*\S+'
  )
ORDER BY submitted_at DESC;

設計判断:どのシナリオに何を使うか

「Forms × BigQuery × セキュリティ監視」を初めて設計するとき、陥りやすい失敗パターンが2つあります。

失敗パターン1:BigQuery Export だけで完結させようとする

BigQuery Export(経路A)は監査ログの継続収集には有効ですが、フォームの回答内容は取得できません。「BigQueryに流せた」と思っても、不正回答を検知するためのデータが揃っていない状態になります。フォームファイルへのアクセス制御の異常(管理者以外がフォームをコピーした、応答シートを外部共有した等)は経路Aで見えますが、それだけでは不正回答の中身は追えません。

失敗パターン2:GAS パイプラインだけで全部やろうとする

回答内容の分析(経路B)は大半のシナリオをカバーできます。一方、「管理者以外がフォームファイルにアクセスした」「応答シートが意図しないユーザーと共有された」といったファイル操作レベルの監視は、Drive 監査ログ(経路A)でないと検知できません。

設計判断の軸は、検知したい脅威のレイヤー(ファイル操作ログ vs. 回答内容)に合わせて経路を組み合わせることです。まず経路Bで回答内容の異常検知を立ち上げ、機密フォームや申請フォームに限定して経路Aの監査ログ確認を追加するのが現実的なステップです。

検知後のアクション設計

SQL が結果を返した後のアクションも、設計に含めておく必要があります。異常を検知しても「誰が何をするか」が決まっていなければ、せっかくのパイプラインが機能しません。

BigQuery のスケジュールクエリ機能を使うと、上記の SQL を日次・週次で自動実行し、結果が出たときだけ GAS の後続スクリプトを使って Slack または Gmail に通知する構成が作れます。通知の粒度は次のように分けると運用しやすいです。

  • 即時通知(GAS フォーム送信トリガーと組み合わせる): 機密キーワード混入(検知4)
  • 日次バッチ(スケジュールクエリ): 業務時間外の大量回答(検知3)
  • 週次レポート: 重複回答の累計(検知1)・時間帯別回答分布(検知2)

Forms の件数が少ない初期段階から仕組みを作っておくと、フォーム数・回答数が増えた後も同じ SQL で監視範囲を広げられます。スケジュールクエリの結果を Looker Studio や Google スプレッドシートで可視化することで、情シス担当者が毎朝確認できる簡易ダッシュボードを比較的低コストで構築できます。

運用上の注意点

パイプラインを設計する際には、コスト・個人情報・GAS の実行上限という3つの観点を押さえておきます。

まず BigQuery の費用です。ストレージとクエリ実行のコストはデータ量とクエリ頻度によって変わります。100名規模の組織でフォーム回答が月に数百〜数千件程度であれば比較的小さな規模に収まりますが、実際のコストは環境によって異なるため、事前に BigQuery の料金計算ツールで見積もりを確認してください。

次に個人情報の取り扱いです。メールアドレスや回答内容を BigQuery に転送・保持する場合、社内のプライバシーポリシーや個人情報管理ルールとの整合を事前に確認してください。特に外部向けアンケートでは、回答者への同意取得や保持期間のポリシーが必要になります。

最後に、GAS の実行上限です。GAS には1回あたりの実行時間や日次の合計実行時間に制限があります。回答件数が多い時間帯に処理が集中すると、BigQuery へのインサートが遅延することがあります。件数が多い場合は、GAS のスケジュールトリガーで定期的にまとめてインサートする構成や、BigQuery 外部テーブルとしてシートをリンクする構成の方が安定します。

GWS の BigQuery 連携設計やセキュリティ監視の仕組みづくりについては、DRASENAS の Google Workspace 支援サービスでもサポートしています。設計フェーズからご相談いただくケースが多いです。

コーポレートITのご相談はお気軽に

この記事で書いたような業務改善・自動化の設計から実装まで、DRASENASではコーポレートITの現場に寄り添った支援を行っています。 「まず相談だけ」でも大歓迎です。DRASENAS 公式サイトからお気軽にどうぞ。

CONTACT

御社の IT 部門、ここにあります。

「ITのことはあまりわからない」── そのような状態からで、まったく問題ございません。まずはお気軽にご相談ください。

一社ずつ、一から。