取引詐欺の検知に使うSQLパターン
(analytics.fixelsmith.com)- 詐欺検知は機械学習よりも先に、テーブルと結合を正しく押さえ、速度・位置・金額・加盟店・時間帯の異常パターンをSQLで見つけることから始まる場合が多い
- Velocity は短時間に同じカード保有者の取引が集中する区間を見つけるもので、時間ウィンドウ・しきい値の調整と誤検知ホワイトリストが必要
- Impossible travel は
LAG()と距離計算により、Chicagoでの決済の7分後にLos Angelesで決済されるような物理的に不可能な移動を、強いクローンカードのシグナルとして捉える - 金額異常 は
$1.00、$99.99、$499.99のようにカードテストやルール回避を示唆する価格帯を探すが、給付取引にはあまり当てはまらない - 加盟店の急増、通常時間帯外の取引、ウィンドウ関数の派生カラムを組み合わせると、取引を複数シグナルでスコア化でき、反復サイクルを数週間から数時間へ短縮できる
取引データから不正の兆候を見つけるSQLパターン
- 詐欺検知は機械学習やグラフデータベースよりも先に、正しいテーブルと結合、そして異常な取引パターンを見つけるSQLから始まることが多い
- クレジットカード、医療請求、EC、POS、政府支援の給付プログラムのように、お金が動きログが残るデータに適用できる
- 新しいデータセットでは通常、速度、物理的に不可能な移動、金額異常、加盟店集中、異常時間帯、ウィンドウ関数ベースのシグナルの順でパターンを積み上げていく
1. Velocity: 短時間で過剰な取引
- 盗まれたカードやアカウントを素早く使い切ろうとする場合、同じカード保有者に短時間で取引が集中するパターンが現れる
- 基本クエリでは直近30日間の取引を時間単位でまとめ、
cardholder_idごとの取引数が基準を超える区間を探す - 重要な調整値は 時間ウィンドウの大きさ と 取引数のしきい値
- 1分、5分、1時間版を並行して回して比較できる
- カードテスト組織は数秒で取引を集中させ、給付不正の組織は半日かけて動くこともあるため、スケールが異なる
- 正常ユーザーでも基準を超えることがある
- 自動販売機を管理する運営者
- プリペイドカードを大量チャージする人
- 最初の探索後には、このような誤検知対象のホワイトリストが必要になる
- スライディングウィンドウ方式では
COUNT(*) OVER (...) RANGE BETWEEN INTERVAL '5 minutes' PRECEDING AND CURRENT ROWで直近5分以内の取引数を計算する QUALIFYは Snowflake, BigQuery, Databricks, Teradata で動作する- Postgresではクエリ全体をCTEで包み、外側でフィルタリングする必要がある
2. Impossible travel: 物理的に不可能な移動
- 1枚のカードがChicagoで決済された7分後にLos Angelesで決済されていたら、そのどちらかは偽物である可能性が高い
- このパターンは クローンカード を見つける強いシグナルで、1枚のカードが数分で遠く離れた2地点に存在する正当な理由はほとんどない
- クエリでは
LAG()で直前取引の時刻と位置を取得し、現在位置と直前位置の間の距離と時間を計算する haversineは 大圏距離 (great-circle distance) を計算する関数- ほとんどのデータウェアハウスで提供されている
- なければ自分で書ける程度の関数でもある
- 例のしきい値は 600mph
- 商用ジェット機の巡航速度が約575mphなので、飛行機でも不可能な速度という意味になる
- 100mphに下げると高速な地上移動も拾えるが、実際の航空旅行者や親が子どもを車で送迎する正常取引まで引っかかり始める
- 同系統で追加で見られるシグナルもある
- 5分以内に同じ州の離れた2都市で取引があれば、地域クローン組織を示唆する可能性がある
- 1時間以内に複数のZIPコードで取引があれば、1地域で動くスキマー組織を示唆する可能性がある
- 10分以内に国境を越える取引は、国際組織のシグナルになりうる
3. Amount anomalies: 特定金額帯の異常取引
- 不正ではよく見られるが、通常利用ではまれな 金額パターン がある
- 例の条件では次の金額帯を探す
$1.00,$5.00,$10.00$99.50以上$100.00未満$499.50以上$500.00未満
- 小さな整数ドル金額は、たいてい カードテスト のシグナル
- カード番号ダンプで得た番号が実際に使えるか確認した後、再販売しようとする流れである
- 実際のカード保有者がちょうど
$1.00の商品を買うケースはまれ - コーヒーは
$4.73、給油は$52.81のように、ぴったり丸い金額ではない可能性が高い
- しきい値直下の金額には別の意味がある
$99.99は、多くの場所で$100から本人確認が必要になるラインを避けようとする形かもしれない$499.99は、$500のATM日次上限を避けようとする形かもしれない- 取引者がルールを知っていて、その下にとどまっているシグナルになる
- 給付取引では 丸い金額パターン はあまり役に立たない
- 給付は同じ形でカードテストされない
- 通常は重複受給者のほうが重要なシグナルになる
4. Suspicious merchants: 加盟店単位の異常集中
- 給油機のカードリーダーのように、特定リーダーがスキマーに感染すると、1件ではなく数十件の不正につながることがある
- そのリーダーを数週間使ったすべてのカードが、誰かのデータベースに入ってしまう可能性がある
- 加盟店の観点では、短期間に互いに無関係なカードの数が通常より大きく増え、取引金額も大きくなる形で現れる
- 単純なしきい値の例では、直近7日間について加盟店ごと・時間単位でまとめ、次を計算する
- ユニークカード数
- 全取引数
- 総取引金額
- ユニークカード数が20を超え、総額が
$5000を超える時間帯を探す
- 固定しきい値には規模補正の問題がある
- Costcoなら90秒でこの基準を超えられる
- 古書店ならほとんど超えない
- より良い方法は、各加盟店をその加盟店自身の過去ベースラインと比較すること
- 直近60日間の取引を時間単位でまとめる
- 各加盟店の過去168時間バケットを基準に平均ユニークカード数を計算する
- 現在のユニークカード数が過去平均の3倍を超える区間を探す
- 168時間バケットとは 過去7日間の時間単位区間
- 日次・週次の季節性が重要だから
- 同じコーヒーショップでも火曜14時と土曜9時ではベースラインが異なる
- 出発点としては 通常の3倍 を使える
- アラートが過剰にあふれない程度には緩い
- 実際に異常な時間帯を捉えるには十分厳しい
5. Off-hours: 個人の通常利用時間外の取引
- ほとんどの人には支出習慣がある
- 9時から5時まで働く人が突然午前3時に給油し始めたら、カードが他人に使われているか、旅行中である可能性がある
- 旅行中かどうかは、ほかのシグナルで追加確認できる
- クエリでは直近90日間についてカード保有者ごと・時間帯ごとの取引数を求め、取引が2回以上あった時間帯だけを通常時間帯として認める
- その後、新規取引の時刻がそのカード保有者の
earliest_hourとlatest_hourの範囲外であれば検知する - 内部クエリの「その時間帯に2件以上」という条件が重要
- 3か月前にたまたまあった深夜の給油1件が通常時間帯に含まれるのを防ぐ
- 基準を「一度あったこと」ではなく 実際の習慣 に合わせる
- 欠点は 履歴データが必要 な点
- 新規アカウントにはベースラインがない
- 新規アカウントには全ユーザーの時間帯パターンを使うか、数か月分たまるまでこのパターンをスキップできる
6. ウィンドウ関数でシグナルを組み合わせる
- ウィンドウ関数パターンは独立した不正タイプというより、前の5つのパターンを組み合わせ可能なシグナルにするための準備作業
- 取引ごとに次の派生カラムを作っておける
- 直前取引からの経過時間:
timestamp - LAG(timestamp) - 加盟店が変わったか: 直前の
merchant_idと現在のmerchant_idを比較 - 直近24時間の累計金額:
SUM(amount) OVER (...) - その日の何件目の取引か:
ROW_NUMBER()
- 直前取引からの経過時間:
- こうしたカラムをマテリアライズしておくと、不正ルールは単純な フィルタ式 にまで縮まる
- カードテスト組織は次の条件で見つけられる
- その日の5件目以降の取引
- 直前取引から60秒未満
- 加盟店が直前取引と異なる
- 新しい不正仮説をエンジニアリングチケットではなくSQLフィルタで表現できれば、反復サイクルは 数週間から数時間 に縮まる
- 結果として、より多くの不正をより速く検知できる
パターンを組み合わせて使う方法
- どれか1つのパターンだけでは十分ではない
- 各パターンには明確な限界がある
- Velocityには、自動販売機運営者のような誤検知がある
- 地理的に不可能な移動は、1つの大都市圏内で起きる不正を見逃す
- 金額異常はカードテストの文脈以外ではあまり当てはまらない
- 異常時間帯ルールには履歴が必要
- 実務では全パターンを回し、各取引を複数シグナルにまたがってスコア化する方法が機能する
- 3つか4つのシグナルに引っかかる取引は、ほぼ常に不正
- 1つのシグナルだけに引っかかる取引は、旅行中の正常なカード保有者によるイレギュラーな利用かもしれない
- 不正検知を初めて始めるなら Velocityから 始めるのがよい
- 有用な量の不正をあぶり出せる
- 正常な活動は比較的あまり拾わない
- 実行コストも低い
- すでに1から5までそろっているなら、次の投資先は ウィンドウ関数ベースの生カラム
- 一度作っておけばチームのすべてのアナリストが使える
- 次の不正パターン追加が別プロジェクトではなくなる
注意点
-
NULL処理
- 実際の取引テーブルはSQL入門書のように
NULLを使わないことが多い - 多くのレガシーシステムでは、「終了日なし」に
9999-12-31、「開始日なし」に0001-01-01のような センチネル値 を使う IS NULLでフィルタすると、このような行を静かに見落とすことがある- 特定テーブルの慣習を確認してから
WHERE句を書く必要がある
- 実際の取引テーブルはSQL入門書のように
-
誤検知
- どのルールでも、異常だが合法である行動をする実際のカード保有者を捕まえる可能性がある
- フラグが付いた案件には 人によるレビュー が必要
- 実際に不正だったものとそうでないものを基準にしきい値を調整するフィードバックループが必要
- 単一ルールで自動ブロックすると顧客を失う可能性がある
-
個人情報
- データにPIIが含まれるなら、適用される データ利用ポリシー を守らなければならない
- まず匿名化またはサンプルデータで作業し、本番データは承認後に使うべき
-
コスト
- 大きなパーティションに対するウィンドウ関数は安価ではない
- 先に日付範囲をフィルタしてからウィンドウ関数を適用する必要がある
- データセット全体の2年分の取引に対して先に
LAG()を実行し、その後でWHEREを付けると、ウェアハウスクレジットの予算を大きく消費しかねない
1件のコメント
Hacker Newsのコメント
実際のカード所有者がちょうど $1.00 の買い物をほとんどしないという基準は、結局のところ販売者がどう価格設定するか次第ではないかと思う
盗んだクレジットカードを試すためにウェブサイトで何かを買うとしても、購入者が価格を自由に決められるわけではない
それに、米国のように価格に税金が含まれていない状況を前提にしすぎているようで、他の地域では きっちりした価格 はごく普通だ
他の基準もうまく機能するのか疑問だ。たとえば直近90日で、普段2件以上取引していた時間帯の外で取引した人をフラグするとしたら、半分くらいの人が引っかかるのではないかと思う
複雑な専門知識を過度に単純化したSQLクエリに落とし込んだ記事なのか、全部推測と創作なのか判然としない。「取引詐欺を捕まえるための6つのSQLパターン」と「ここには私が実際に手がけたことや見たことは何もない」という文が矛盾している
普通は午前2時にガソリンやコーヒーや軽食を買ったりしないが、ごくまれにそういうことがあるなら個人的な緊急事態である可能性が高く、その最中に銀行へ電話したいとは思わない
日和見的な泥棒もその時間に活動しうるのは分かるが、誤検知コスト も確実に存在する
それに、10、20、50ユーロのようにあらかじめ決めた金額を要求するガソリンスタンドもある
すると詐欺の疑いがあるとしてカードが止められ、かなり腹が立った。午前2時に酔った状態で対処したいことではなかった
もしかすると自分自身から守ってくれたのかもしれないが、それでも不便だった
それに、ほぼ100%の精度を期待しないこうしたヒューリスティックなパターン認識こそ、AIが得意であるべき領域ではないかと思う
「10分以内の国境越えは国際組織」という基準は、ヨーロッパの国境近接地域 に住む普通の人たちにも当てはまりうる
カード非対面取引は除外するとしても、すべての加盟店所在地が正確に設定され、すべての販売が実店舗で行われ、移動販売のようなものはなく、すべての取引がオンライン処理されると誤って想定しているように見える
最後まで読むと、中身が薄く、互いに矛盾する助言が露呈する。ほぼ確実に LLM生成記事 っぽい
「あなたのチーム」はどの単一パターンにも依存すべきでないと言いながら、パターン1だけでも「有用な量の詐欺」を明らかにできると言っている
「チームのすべてのアナリストはそれら、つまりウィンドウ関数が手に入れば使うだろうし、次の詐欺パターンを追加することがプロジェクトではなくなる」といった妙な文もある
また、ほぼすべての例が
IS NULLを使っていないのに、IS NULLフィルタリングが適用されないことがあるという無関係な話が出てきて、唯一使っている例も別の文脈だ全体として 質が低くて長すぎる記事 だ
Hacker News、これは指摘しておくべきだ
「Fixel Smith」は AIが作った人物 で、記事は詐欺分析とほとんど関係がない。この名前はミュージシャン(1)、小説家(2)、詐欺アナリスト(3)、インフルエンサー(4)など、想像できるほぼあらゆる人格として使われている
220点以上ついてコメントも70件を超えているのに、この投稿がかなり偽物っぽいと気づいた人はほとんどおらず、AI生成の人物だと見抜いた人もいない
https://www.amazon.it/Forged-Soundtrack-Explicit-Fixel-Smith...
https://fixelsmith.com
https://analytics.fixelsmith.com/
https://www.instagram.com/fixeltales/
このAIの洪水がコミュニティの判断力について不快な真実を示しているのか、それとも既存の防御策の失敗で、変えさえすれば済む話なのか気になる
すべてのコメントが善意で書かれたものだと仮定するなら、ここですら AIリテラシー が低いのはかなり心配だ
小説は分析記事とほとんど関係がなく、分析記事は LLM文体 を帯びているようで、全体として怪しい。元記事のテーマが詐欺だと考えると皮肉だ
正直、私はたいてい署名欄すら見ないし、サイトの他の部分はなおさら見ない
内容が作り話かどうかは不明だが、LLMが書いたのか小説なのかを推測しなくても、記事の中身自体を批判することはできる。もっと具体的な欠陥がいくらでもある
私たちはオープンソースのセキュリティフレームワーク tirreno を開発している
ここで説明されているアプローチには疑問がある。たとえば不可能移動は正当で広く使われる手法だが、これはIPアドレスベースのオンラインユーザー行動に関するものだ
tirrenoには、IPがApple RelayやVPN/Tor由来であることが明らかな場合のための別ルールがあり、それらは別個のフラグになっている
一部または全部の例はLLM生成だと思う。文脈が混ざっているし、カード決済でGPS位置情報を大規模に収集しているところは実際には存在しないからだ
これは「根拠データなしにSQLクエリへエンコードした ルールベースロジック 」に近い
閾値は山ほどあるが、その閾値に意味があることを示すデータはない
「取引データの詐欺検知はたいていSQLであり、機械学習でもグラフデータベースでもGartnerが今年持ち上げている何かでもない」というような断定は、プログラムインテグリティ 業務全体を扱う場合にのみ正当化できるだろう
問題領域を解決するなら、もっと単純で粗い方法のほうがよいこともある
フィンテックの顧客は通常、今まさに起きている取引が不正かどうかを知りたがり、高次元データに対して数ミリ秒以内の回答を求める。リレーショナルデータベースでは、この種のリアルタイム制約に対応するには規模的に難しい作業であり、その代わり履歴データの積み込みのような別用途で使われる
だからこそインメモリデータベース、ストリーム処理エンジン、そして機械学習まで登場する
それでも筆者のいくつかの指摘は妥当で、特にノイズの多いアラートを扱う問題は性能エンジニアリングを超えた一般的な課題なので、次の記事には期待している
防止では常にレイテンシ要件、利用可能なデータ、不完全なユーザー行動像に制約される。機械学習とルールで高速な判断を下して大半のケースを処理するが、そうした制約のため、すべての不正を正確に防ぐことはできない
検知はその後の結果を扱う。承認済み取引をアナリストチームが分析して不正の兆候を探すのが一般的だ。チャージバックや顧客苦情のような外部シグナルがないタイプの不正では、特に重要になる。プラットフォームインテグリティがその一例であり、フィンテックのマネーロンダリング対策システムも不正を見つけに行かなければならない
両者が補完的なのは、検知された取引が次の防止モデルを学習・評価するための ラベル になるからだ
シカゴでカードがスワイプされ、7分後にロサンゼルスでまたスワイプされたら、どちらか一方は偽物だという話だったが、オンラインショッピング ではどう機能するのか気になる
ソファに座ってAmazonで買い物したら、住所はどこに登録されるのだろう?
それに、夫婦がオンラインアカウントを共有していて、一方が旅行中に保存済みカード情報で購入するような境界事例もありそうだ
小売業者と銀行はこの違いを区別できる
「この方式は履歴が蓄積されるまで機能せず、新規アカウントにはベースラインがない」というのは、過小評価されている 顧客体験 の要素だ
新しい顧客だったり、新しいパターンを示したりするときにカードが拒否されれば、ソフトウェアはうまくやっているように感じる
しかし、自分が認証した過去履歴があるのに取引を拒否されると、単純で被害妄想的なアルゴリズムのせいで腹が立つ
不正取引は最終的に取消しや返金で銀行が損失を被る。拒否された取引は怒った顧客を1人作るだけで、顧客は文句を言ったあとすぐ忘れる。だから外部化されたコストの負担は顧客へ向かう
したがって銀行には、より慎重な側に誤る、つまり誤検知があっても取引を拒否するインセンティブがある
機械学習の本質は、こうしたルールをデータから学ぶことではないかと思う
正しいアプローチは、機械学習モデルで不正に対応するパターンを見つけ、その中で意味のあるものがあるか評価することだと思う。そうすれば 新しい仮説 を発見できるかもしれない
人間のアナリストは、特定の取引がなぜ拒否されたのか、そして不利な決定を避けるには何を変えるべきだったのかを、コンプライアンスチームに 5分で読めるメール 1通で説明できなければならない
機械学習で1つ問題を直すと、まだ顕在化していない新しい問題が2つ生まれることがよくある。時間とともに変化したときの回帰や予期しない副作用という点では、SQLのほうがたいてい驚きが少ない