はじめに:
SaaS型ECプラットフォームにおけるリソース保護の死角
弊社のSaaS型ECプラットフォームでは、多数の店舗がそれぞれ独自の正規ドメインを割り当てられ、同一基盤上で並行してトランザクションを処理しています。こうした環境では、自社のフロントエンド資産やブランドが想定外のドメインで利用されていないかを把握し、必要に応じて調査できる状態を作ることが、プラットフォーム運営者の重要な責務になります。
近年はAIによる脆弱性探索や攻撃の自動化が進み、攻撃や模倣の試行コストが下がりつつあります。この流れは、防御設計において「すべてを事前に防ぐ」だけでなく「発生した兆候をいかに早く検知するか」の重要性を高めています。本記事で扱うコピーサイト疑いの検知も、無断利用を事前に完全に防ぐ仕組みではなく、正規フロントエンド資産が管理外ドメインで実行された可能性を計測データから発見し、調査着手までの時間(MTTD:Mean Time To Detect)を短縮する早期検知レイヤーです。
一点、本記事を通じた前提を明確にしておきます。本方式は、対象ドメインがコピーサイトだと自動的に断定する仕組みではありません。 ねらいは、担当者が調査すべき対象を早期に発見し、トリアージに着手するまでの時間を縮めることです。以降では「調査シグナル」を、断定ではなく調査の起点となる観測値の意味で使います。
ウェブアプリケーションセキュリティでは、管理外サイトからのiframe埋め込みや許可されないオリジンからのAPIアクセスを防ぐ手段として、Content Security Policy (CSP)のframe-ancestorsや Cross-Origin Resource Sharing (CORS)が有効です。
ただしこれらが対象とするのは埋め込みやクロスオリジンアクセスの制御であり、HTMLや静的アセットが丸ごとスクレイピングされ、攻撃者自身のインフラ・別ドメインでホストされるケースには死角が残ります。この場合、元サーバーにはリクエストが届かないため、CSP・CORSやサーバーログの監視だけでは外部での稼働を検知できません。
本記事では、フロントエンドのパフォーマンス監視基盤として導入している「New Relic Browser」の仕様を活用し、管理外ドメインで稼働している疑いのあるサイト(無断転載やクローンサイト等)について、New Relic Browser Agent が稼働した痕跡を調査シグナルとして観測し、日次で通知・トリアージする監視アーキテクチャの構築手法を解説します。
全体像のイメージ
先に全体像を示します。詳細は以降の各セクションで解説します。
※図中の『New Relicタグ』は、本文の New Relic Browser Agent(計測エージェント)と同じものを指します。
監視アーキテクチャの着眼点:
Browserイベントを「調査シグナル」として利用する
New Relic Browserを導入したページがロードされると、パフォーマンスを計測するJavaScriptエージェントが発火し、収集データをNew Relicの収集エンドポイントへ送信します。
ここで着目すべきは、「コピーサイトがHTMLやJavaScriptを精査せず無差別にコピーして構築された場合、New Relic Browserの計測エージェントも改変されないままコピー先のドメインで実行される可能性がある」という点です。
この前提に立つと、次の連鎖が起こります。
- 正規テナントサイトのHTML/JSが外部の主体にスクレイピングされる
- スクリプト群が管理外の別ドメインにデプロイ・公開される
- エンドユーザーがその管理外ドメインにアクセスし、ページがレンダリングされる
- ページ内のNew Relicエージェントが仕様通り発火し、PageViewイベントが正規のNew Relicアカウントへ送信される
- 計測データ上に「許可した覚えのない管理外ドメインからのPageViewイベント」が記録される
このメカニズムを応用すれば、想定外のドメインで発生したNew Relic Browserイベントを、管理外で稼働している可能性のあるサイトを見つける調査シグナルとして利用できます。本来のパフォーマンス監視を超え、計測データをブランド保護・リソース悪用検知の早期警戒シグナルとして活用するアプローチです。
前提条件:
Domain Conditions による取り込み制御との関係
本方式は、New Relic BrowserのDomain Conditionsの設定状態に依存します。
「Allow only」方式で正規ドメインからの取り込みのみを厳格に許可している場合、コピー先ドメインが許可条件に一致しなければ、その報告ページURL由来のBrowserデータは取り込み対象外となり、本方式では観測できません。ここでDomain Conditionsは、エージェントの実行を止めるのではなく、報告されたページURLに基づいてデータ収集を制御する仕組みである点に注意してください1。本方式が機能するのは、Domain Conditionsが未設定、あるいは「Deny only」で運用されている(未登録ドメインのデータも一旦取り込んでいる)環境です。
重要なのは、Domain Conditions(入口制御)と本方式(観測ロジック)が代替ではなく目的の異なる補完関係である点です。前者は不要・意図しないイベントを取り込み前に止め、後者はすでに取り込まれたイベントから管理外ドメインの痕跡を見つけます。以降はこの棲み分けを前提に、観測ロジックへ焦点を当てます。仕様の詳細とSaaS環境での設計上の論点は、本筋から外れるため折りたたみに記載します。
Domain Conditionsの仕様と本観測ロジックの棲み分け(詳細)
Domain Conditionsは、Browserアプリごとに「どのドメインのページから来たデータを取り込むか」を許可・拒否する機能です1。New Relicが受け取ったBrowserデータを、その「ページのドメイン」に基づいて取り込むか捨てるかを判定する、いわば取り込み側のフィルタで、開発・検証環境など管理対象外ドメインからのデータ混入を抑制できます。
Domain ConditionsはBrowserデータの取り込み可否を制御する機能であり、Agent実行後に収集されるAjaxRequest等の個別イベントについて計測対象を制御するものではありません。そのためAjax Deny Listの代替ではなく、意図しないドメインや環境からのBrowserデータ混入を抑える入口制御と位置づけるのが適切です。AjaxRequestの収集対象を制御したい場合はAjax Deny ListやBrowser Agent側の設定、実装側での計測制御を検討します。
SaaS型ECプラットフォームでは、テナントごとに独自ドメインが割り当てられ、正規ドメインの一覧も日々変化します。さらに Domain Conditions の条件は最大10件という上限があるため1、数千テナントを「Allow only」で厳格運用するには、サフィックス一致での集約を前提にしても運用設計上の工夫が要ります。セキュリティやコスト制御の観点で「Allow only」は有力ですが、設定を有効化すれば済むものではなく、ドメインリストの更新漏れによる正規データの欠落、例外ドメインの扱い、運用フロー整備、インジェストコストとのバランスといった論点が伴います。
本方式は、この前提を踏まえ、すでに取り込まれている Browser イベントから管理外ドメインの痕跡を見つけ、調査・トリアージにつなげる補助的な監視アーキテクチャです。
判定ロジック:
Lookupテーブルとアンチジョイン(差集合抽出)の実装
管理外ドメインをあぶり出すには、蓄積されたPageViewのドメイン集合から、事前に許可された正規ドメインの集合を差し引きます。具体的にはPageViewとLookupテーブルを結合し、Lookup側に一致が無いイベントだけを残す、SQLでいうアンチジョインです。
実装に入る前に、本ロジックの検知対象を整理します。
| 項目 | 内容 |
|---|---|
| 観測対象 | PageView イベント |
| 比較キー | domain属性を正規化した基底ホスト(サービス別サブドメイン・www. を除去) |
| 正規集合 | 店舗管理マスタ由来の正規ドメイン(Lookup) |
| 検出対象 | 正規集合に存在しないホスト |
| 除外対象 | 既知のプロキシ・開発環境・アーカイブ・検証環境 |
SaaSでは正規ドメインのリストは常に変動します。弊社では、業務DBの店舗管理マスタから最新の正規ドメイン一覧を抽出し、New RelicのLookup API経由で同期するシェルスクリプトを、cronで日次実行しています。
構成の概念を示すNRQL
ポイントは、URL全体をパースせず、PageView の domain属性(ホスト名)を使うことです。domainにはサービス別サブドメイン(shop. support. など)やwww.が含まれるため、capture() でこれらを剥がして基底ホストに正規化します。PageView側とLookup側を同じルールで正規化してから突き合わせることで、サブドメイン違いやwww.の有無による偽陽性を防げます。
NRQLの構文面では次の3点に注意します。
- JOIN句は
FROMの直後に置く2 -
capture()の正規表現は入力全体にマッチする(部分一致は末尾に.*が必要)3 -
capture()をWITHで変数化する場合、名前付きキャプチャの出力名をAS (pvHost)のように括弧で囲う
WITH
-- PageView の domain 属性から、サービス別サブドメイン(shop. や support. 等)と www. を除外してベースとなるホスト名を取得
capture(domain, r'^(((shop|support|blog|app|api)|www)\.)?(?P<pvHost>[^:/]+).*') AS (pvHost)
FROM PageView
LEFT JOIN (
-- 正規ドメイン一覧(Lookup)も同じルールで基底ホストへ正規化して突き合わせる
FROM lookup(authorized_domains)
SELECT tenantKey, authorizedDomain,
capture(authorizedDomain, r'^(((shop|support|blog|app|api)|www)\.)?(?P<lookupHost>[^:/]+).*') AS lookupHost
LIMIT 20000
) ON pvHost = lookupHost
SELECT count(*)
WHERE appName = 'YOUR_BROWSER_APP' -- 対象のBrowserアプリに限定
AND tenantKey IS NULL -- Lookupに一致しない = 正規ドメイン集合に存在しない
AND domain IS NOT NULL
-- 既知の無害な例外を除外(翻訳プロキシ/検証環境など。環境に合わせて追加)
AND pvHost != 'localhost'
AND pvHost NOT LIKE '%.example-proxy.%'
FACET domain AS 'ドメイン'
SINCE 1 day ago
LIMIT MAX
このNRQLは構文の組み立て方を示すテンプレートです。 Lookupテーブル名(authorized_domains)や列名(tenantKey / authorizedDomain)、appName、正規表現は、ご自身の環境に合わせて調整し、必ず実行して検証してください。
比較キーは pageUrl ではなく domain 属性を使います。FROM PageView SELECT keyset(), uniques(domain) WHERE appName = 'YOUR_BROWSER_APP' SINCE 1 day ago などで実際に記録されている値を確認してから正規表現を調整してください4。
クエリ設計における技術的制約
上記NRQLをプロダクションで安定稼働させるには、New Relicの基盤仕様に基づく制約の理解が欠かせません。本筋から逸れるため、詳細な仕様と回避策は以下に折りたたみます。
1. サブクエリJOINの取得上限とLookupテーブルの特例
通常のイベントデータを用いたサブクエリJOINでは、結果セットは最大5,000件に制限されます2。しかし外部データを参照する lookup() をサブクエリのソースとする場合に限り、仕様により最大20,000件まで拡張されます5。数千テナントを抱える環境でも、この特例により「5,000件の壁」に阻まれず1回のクエリで全ドメインを結合評価できます。なおこの拡張はLookupを参照するサブクエリ側に効くもので、外側クエリのLIMITは外側自体もLookupを参照しない限り標準上限に縛られます5。
2. ホスト名の取得と domain 属性
ホスト名は pageUrl をパースするより、PageView のdomain属性を使うのが簡潔です(スキームやパスを含まないため)。ただしdomainにはサービス別サブドメインやwww.が含まれるので、capture()でdomainを基底ホストへ正規化します。pageUrl を使う場合は、URLがNew Relic側で正規化・グルーピングされ、クエリパラメータやハッシュフラグメントが除去される場合がある点に注意が必要です43。
3. JOIN条件におけるデータ型とカーディナリティ
NRQLのJOINの ON 句は等価条件のみをサポートし、両辺のデータ型が完全一致している必要があります2。またJOINのカーディナリティには1:100の制限があり、1つの結合キーがサブクエリ側の100行を超えるとエラーになります。重複排除を徹底し、クリーンな結合関係を保つことが重要です2。
4. ドメイン正規化とLookupテーブルの設計
比較の際は、PageView側とLookup側の両方を同じ正規表現で正規化し、サービス別サブドメインやwww.を吸収するのが前提です。そのうえで、次のような表記揺れも考慮します。
- 大文字小文字、
www.の有無、末尾ドット、ポート番号 - punycode / 日本語ドメイン(IDN)の表記
- サブドメイン単位で許可するか、eTLD+1(例:
example.com)単位で見るか -
shop.example.comとexample.comを同一視するか -
stg.example.comなどの検証環境を許可対象に含めるか
また、Lookupテーブルにドメイン列だけを持たせると、通知後に「どの店舗の正規ドメインか」「いつ追加・廃止されたか」が追えません。authorizedDomain, tenantKey, environment, status, source, updatedAt のような列を持たせておくと、トリアージと棚卸しが容易になります。
運用自動化:
Workflow Automationによる日次通知
早期検知という観点では、異常を検知した瞬間に発報するストリーミングアラートが理想に思えます。しかし本システムでは Workflow Automationによるスケジュール実行(日次バッチ通知) を採用しています。これは、本ロジックが即時性より「継続的に観測し、調査対象を見逃さないこと」を重視するユースケースであることに加え、New Relicのアーキテクチャ上の制約を踏まえた現実的な選択です。
この選択には明確な理由があります。New Relicのアラート評価エンジンは、データがシステムを通過する瞬間に単一パスでリアルタイム評価を行います。一方、サブクエリやJOIN、外部参照の lookup() を含むクエリは複数回のデータ走査を要するため、ストリーミングアラートの条件としては登録できません2。したがって、アラートの代わりにWorkflow Automationによる定期実行が現実的な選択肢となりました。
日次で以下を自動実行するワークフローを構築しています。
- newrelic.nrdb.query
- NRQLを発行し、「管理外ドメインのユニーク総数」や「ドメインTop 5」をJSONで取得
- slack.chat.postMessage
- 取得したJSONの変数をテンプレート内で展開し、整形レポートとしてSlackへ配送
【Slack通知ペイロードの構成例】
【日次レポート】管理外ドメインからの計測データ観測
直近24時間において、登録外のドメインから自社Browserエージェントの稼働を N 件観測しました。
これはコピーサイト等を断定するものではありませんが、正規フロントエンド資産が想定外の場所で実行された可能性を示す調査シグナルです。
観測頻度上位の未登録ドメイン Top5:
・example[.]com (観測数: 123件)
・example2[.]net (観測数: 45件)
※ダッシュボードへ遷移し、突発的なトレンド変化、継続的な観測、不審なホスト名が含まれていないかをトリアージしてください。
なお、通知を受けてすぐ調査に移れるよう、この差集合抽出NRQLを可視化した専用ダッシュボードを用意し、Slack通知本文にそのリンクを含めています。
継続的チューニング:
ノイズの排除とトリアージプロセスの確立
SaaS環境では、管理外ドメインからのシグナルに常に大量のノイズが混入します。代表的な「既知の無害な例外」は次の通りです。
- プロキシ型サービスと機械翻訳: Google翻訳(
translate.goog)などのプロキシ経由のアクセス - ローカル・開発環境:
localhostや127.0.0.1からのアクセス - アーカイブとキャッシュ: Wayback MachineなどのWebアーカイブによるクロール
これらはNRQLのWHERE句で NOT LIKE を用いて地道に除外条件を追加していく、継続的なチューニングが不可欠です。早期検知は通知を増やせばよいわけではありません。ノイズが多すぎると担当者が通知を確認しなくなり、検知能力はかえって低下します。MTTD短縮には、検知ロジックだけでなく、誤検知を減らして調査すべきシグナルの密度を高めるチューニングも重要です6。
通知を受けた担当者は専用ダッシュボードへ遷移し、該当ドメインのアクセスの時系列推移(スパイクか継続的か)やリクエスト元の地理的分布を多角的に分析し、真に悪意あるコピーサイトの疑いがあるかをトリアージします。
トリアージの具体手順(例)
- 観測回数が少数の単発か、継続的かを確認する
- translate.goog、Wayback Machine、localhost などの既知の無害な例外を除外する
- ホスト名を urlscan.io / VirusTotal / Google Safe Browsing などで確認する
- 実際にアクセスする場合は、隔離環境やスクリーンショット取得を用いる
- 正規店舗ドメインの登録漏れ、または廃止済みドメインでないかを確認する
- 悪性の疑いが強ければ、法務・CS・インフラ・セキュリティへエスカレーションする
本方式の限界:
検知できないケース(偽陰性)
本方式は調査シグナルを早期に拾うための仕組みであり、すべてのコピーサイトを捕捉できるわけではありません。とくに次のようなケースは原理的に検知できません。
- コピー時に、攻撃者がNew Relic Browser Agent関連のコードを削除している
- コピーサイト側のCSPやネットワーク制約により、New Relicへのデータ送信が失敗する(コピー先でCSPヘッダが再現されるか、Agentの読み込み・送信が許可されるかは配信方法に依存)
- Domain Conditions の「Allow only」運用により、未許可ドメインのデータが取り込まれない
- Botやヘッドレスブラウザがアクセスし、JavaScriptを実行しない
- HTMLではなくスクリーンショットや静的画像として模倣されている
- Browser Agentが読み込まれる前にページが離脱・失敗する
したがって本方式は「コピーサイトの網羅的な検知」ではなく、「正規Browser Agentがそのまま残ったコピーを早期に拾う」レイヤーと理解するのが正確です。偽陽性(ノイズ)と偽陰性の両方を前提に、他の防御策と組み合わせて運用します。
おわりに
本記事では、本来パフォーマンス監視のために収集しているNew Relic Browserイベントを、管理外ドメインでの予期せぬ稼働を見つける調査シグナルとして活用するアーキテクチャを紹介しました。
オブザーバビリティ基盤は、単なるサーバーの死活監視にとどまりません。業務ドメインのコンテキスト(正規店舗のリスト)と日常的に収集されている計測データを動的に結合し、システムへの「違和感」をデータドリブンに抽出することで、ブランド保護やリソース悪用検知といったセキュリティ、さらに上位のビジネス課題を解く強力な武器になります。AIによって攻撃や模倣の試行コストが下がる時代に、すべての不正利用を事前に防ぎきることは現実的ではありません。重要なのは、防御策を講じたうえで、なお発生し得る想定外の稼働や悪用の兆候を継続的に観測できる状態を持つことです。
最後に本方式の位置づけを2点で整理します。第一に、これはコピーサイトを確定判定する仕組みではなく、調査すべき違和感を早く拾いトリアージに進むためのMTTD短縮施策です。第二に、Domain Conditions(取り込み前の入口制御)を代替するものではなく、すでに取り込まれたイベントから管理外ドメインの痕跡を棚卸しする観測ロジックとして、両者は補完関係にあります。多数のテナント独自ドメインを抱え、正規ドメイン一覧が変化し続けるSaaS環境では、取り込み制御と観測ロジックの両方を運用可能な形で設計することが重要です。
本レポートが、計測データの独創的な活用方法を模索するエンジニアにとって有用な技術的示唆となれば幸いです。
