账户接管欺诈

1. 简介

账户接管(Account Takeover, ATO)欺诈是一种复杂的身份盗窃形式,网络犯罪分子通过非法手段获取合法用户账户的访问权限。这种日益严重的威胁影响着从金融服务到社交媒体平台等各类账户,对个人和组织都造成了重大影响。根据最新研究,22% 的美国成年人曾遭受过 ATO 欺诈,平均每人损失达 12,000 美元。此类欺诈通常涉及通过网络钓鱼、数据泄露或社会工程学等手段窃取凭据,随后利用账户进行未经授权的交易或实施其他欺诈活动。随着数字服务的扩展,强大的检测和预防策略对于防范这种不断演变的威胁变得愈发关键。

2. 场景

账户接管类型

  • 金融账户欺诈:未经授权的转账、欺诈性购买以及信用卡申请

  • 电子邮件账户入侵:访问个人信息、重置密码以及进一步实施账户接管

  • 社交媒体劫持:身份冒充、诈骗信息散布以及社会工程学攻击

问题的严重性

  • 影响广泛:22% 的美国成年人曾是账户接管的受害者

  • 经济损失:平均每起事件导致个人损失 12,000 美元

  • 商业影响:严重的声誉受损及潜在的法律后果

  • 日益复杂:越来越多地使用自动化工具和人工智能进行大规模攻击

挑战

  • 复杂的攻击向量:通过网络钓鱼、恶意软件和社会工程学存在多个入口点

  • 撞库攻击(Credential Stuffing):使用窃取的用户名/密码组合进行的自动化攻击

  • 设备欺骗(Device Spoofing):欺诈者使用先进技术绕过设备指纹识别

  • 绕过身份验证:规避多因素身份验证的复杂手段

  • 快速的连续更改:攻击者快速修改联系信息并添加外部账户

  • 事件速度检测:区分合法的紧急变更与自动化的欺诈行为

  • 取证复杂性:追踪攻击过程中发生了哪些变动,以便进行调查和客户恢复

3. 解决方案

图数据库为检测和预防账户接管欺诈提供了一种强大的方法。通过将用户行为、设备交互和账户活动的复杂网络建模为连接的网络,图技术能够识别传统系统可能漏掉的可疑模式。这种方法对于 ATO 欺诈尤为有效,因为 ATO 欺诈需要同时分析多个数据点及其之间的关联。

3.1. 图数据库如何提供帮助?

  1. 设备指纹识别:Neo4j 可以追踪用户账户、设备和 IP 地址之间的关联,从而识别可疑的登录模式和潜在的撞库攻击。

  2. 行为分析:图数据库擅长模拟正常的用户行为模式并检测异常,例如:

    • 不寻常的登录时间或地点

    • 交易模式的可疑变化

    • 意外的账户设置修改

    • 应用程序内异常的导航模式

    • 预示自动化攻击的快速连续账户更改

  3. 身份验证网络:创建全面的身份图谱,连接:

    • 用户账户和关联的电子邮件地址

    • 电话号码和身份验证方法

    • 设备指纹和登录位置

    • 交易模式和受益人关系

  4. 实时检测:Neo4j 支持:

    • 对照已知模式实时验证登录尝试

    • 对交易序列进行实时分析

    • 立即识别可疑的 IP 地址或设备

    • 基于图模式的动态风险评分

  5. 网络分析:通过以下方式发现复杂的欺诈团伙:

    • 识别受损账户之间的共有属性

    • 检测可疑活动簇

    • 追踪撞库攻击的传播路径

    • 映射已知欺诈实体之间的关系

  6. 事件序列追踪:追踪按时间顺序排列的事件链,以检测账户接管模式

    • 监控账户修改的速度(每分钟事件数)

    • 识别从访问到资金转账的完整攻击生命周期

    • 保留旧值与新值的取证轨迹,以供调查使用

    • 通过恒定的时间间隔检测自动化攻击模式

4. 建模

本节演示了如何使用 Neo4j 构建用于检测账户接管欺诈的数据结构。示例包含一个完整的独立数据集,展示了多种欺诈模式。

模型包括:

  • 基础实体:用于追踪访问模式的客户(Customer)、设备(Device)、会话(Session)、IP、位置(Location)节点

  • 事件节点:身份验证(Authentication)、更改电话(ChangePhone)、更改邮箱(ChangeEmail)、更改地址(ChangeAddress)、添加外部账户(AddExternalAccount)、转账(Transfer)

  • 时间链:在时间序列上链接事件的 :NEXT 关系

  • 取证追踪:为联系信息更改保留旧值与新值

此方法演示了基于事件的欺诈检测模式。如需更详细的规范和可扩展模型,请参阅 欺诈事件序列数据模型

4.1. 数据模型

4.1.1 必填字段

Customer(客户)节点

  • customerId:客户唯一标识符

Device(设备)节点

  • deviceId:设备唯一标识符

  • deviceType:设备类型(移动端、桌面端、平板)

  • userAgent:浏览器/应用的用户代理字符串

  • createdAt:首次记录设备的时间戳

IP 节点

  • ipAddress:IP 地址

  • createdAt:首次观察到 IP 的时间戳

ISP(互联网服务提供商)节点

  • name:互联网服务提供商名称

  • createdAt:首次记录 ISP 的时间戳

Location(位置)节点

  • city:城市名称

  • postCode:邮政编码(可选)

  • country:国家代码

  • latitude:地理纬度(可选)

  • longitude:地理经度(可选)

  • createdAt:首次记录位置的时间戳

Session(会话)节点

  • sessionId:唯一会话标识符

  • status:会话状态(成功、失败、可疑)

  • createdAt:会话启动的时间戳

Account(账户)节点

  • accountNumber:唯一账户号码

Email(邮箱)节点

  • address:电子邮件地址

  • domain:电子邮件域名

  • createdAt:首次记录邮箱的时间戳

Phone(电话)节点

  • number:电话号码

  • countryCode:国际拨号代码

  • createdAt:首次记录电话的时间戳

Address(地址)节点

  • addressLine1:地址第一行

  • addressLine2:地址详细信息(可选)

  • postTown:邮政城镇或城市

  • postCode:邮政编码

  • region:县、省或行政区(可选)

  • latitude:地理纬度(可选)

  • longitude:地理经度(可选)

  • createdAt:首次记录地址的时间戳

Transaction(交易)节点

  • transactionId:唯一交易标识符

  • amount:交易金额

  • currency:三字母货币代码(例如 "GBP", "USD")

  • date:交易处理的时间戳

  • message:付款参考或说明(可选)

  • type:付款方式或交易类型(可选)

Country(国家)节点

  • code:两字母 ISO 国家代码

  • name:国家名称

事件节点(用于追踪账户接管序列)

Authentication(身份验证)节点

  • method:使用的身份验证方法(例如 "email", "phone_number")

  • status:身份验证尝试的状态(例如 "success", "failed")

  • createdAt:建立身份验证的时间戳

ChangePhone(更改电话)节点

  • createdAt:电话号码更改的时间戳

ChangeEmail(更改邮箱)节点

  • createdAt:电子邮件地址更改的时间戳

ChangeAddress(更改地址)节点

  • createdAt:地址更改的时间戳

AddExternalAccount(添加外部账户)节点

  • createdAt:添加外部账户的时间戳

Transfer(转账)节点

  • createdAt:执行转账的时间戳

关系

  • USED_BY:客户使用的设备

  • USES_IP:会话使用的 IP 地址

  • SESSION_USES_DEVICE:会话使用的设备

  • HAS_ACCOUNT:客户拥有的账户

  • HAS_EMAIL:客户拥有的邮箱

  • HAS_PHONE:客户拥有的电话

  • HAS_ADDRESS:客户拥有的地址

  • IS_ALLOCATED_TO:分配给 ISP 的 IP

  • LOCATED_IN:位于某国家的 IP/位置/地址

  • IS_HOSTED:在某国家托管的账户

  • PERFORMS:账户执行的交易

  • BENEFITS_TO:交易收益方账户

  • HAS_SESSION:客户拥有的会话

基于事件的关系

  • CONNECTS:客户通过身份验证连接

  • NEXT:按时间顺序链接事件(事件→事件)

  • HAS_AUTHENTICATION:会话包含的身份验证事件

  • HAS_CHANGE_PHONE:会话包含的电话更改事件

  • HAS_CHANGE_EMAIL:会话包含的邮箱更改事件

  • HAS_CHANGE_ADDRESS:会话包含的地址更改事件

  • HAS_ADD_EXTERNAL_ACCOUNT:会话包含的外部账户添加事件

  • HAS_TRANSFER:会话包含的转账事件

  • OLD_PHONE:链接到之前的电话号码(更改电话→电话)

  • NEW_PHONE:链接到新的电话号码(更改电话→电话)

  • OLD_EMAIL:链接到之前的邮箱(更改邮箱→邮箱)

  • NEW_EMAIL:链接到新的邮箱(更改邮箱→邮箱)

  • OLD_ADDRESS:链接到之前的地址(更改地址→地址)

  • NEW_ADDRESS:链接到新的地址(更改地址→地址)

  • ADD_ACCOUNT:链接到添加的账户(添加外部账户→账户)

  • HAS_TRANSACTION:链接到交易(转账→交易)

4.2. 演示数据

以下 Cypher 代码创建了一个完整的示例,展示了多种账户接管欺诈模式

//--------------------
// Create Countries
//--------------------
CREATE (uk:Country {code: "GB", name: "United Kingdom"})
CREATE (us:Country {code: "US", name: "United States"})
CREATE (cn:Country {code: "CN", name: "China"})
CREATE (ng:Country {code: "NG", name: "Nigeria"})

//--------------------
// Create Customers
//--------------------
CREATE (c1:Customer {customerId: "CUS001"})
CREATE (c2:Customer {customerId: "CUS002"})
CREATE (c3:Customer {customerId: "CUS003"})

//--------------------
// Create Devices
//--------------------
CREATE (d1:Device {deviceId: "DEV001", deviceType: "desktop", userAgent: "Mozilla/5.0 Chrome/91.0", createdAt: datetime("2024-03-01T09:00:00")})
CREATE (d2:Device {deviceId: "DEV002", deviceType: "mobile", userAgent: "Mozilla/5.0 Mobile Safari/537.36", createdAt: datetime("2024-03-01T09:30:00")})
CREATE (d3:Device {deviceId: "SUSPICIOUS001", deviceType: "desktop", userAgent: "Mozilla/5.0 Firefox/89.0", createdAt: datetime("2024-03-01T10:00:00")})

//--------------------
// Create ISPs and Locations
//--------------------
CREATE (isp1:ISP {name: "BT", createdAt: datetime("2024-01-01T00:00:00")})
CREATE (isp2:ISP {name: "Orange", createdAt: datetime("2024-01-01T00:00:00")})
CREATE (isp3:ISP {name: "Verizon", createdAt: datetime("2024-01-01T00:00:00")})
CREATE (isp4:ISP {name: "China Telecom", createdAt: datetime("2024-01-01T00:00:00")})

//
// Create Location nodes
//
CREATE (l1:Location {city: "London", postCode: "XX30 1XX", country: "UK", latitude: 51.5074, longitude: -0.1278, createdAt: datetime("2024-01-01T00:00:00")})
CREATE (l2:Location {city: "Paris", postCode: "75001", country: "France", latitude: 48.8566, longitude: 2.3522, createdAt: datetime("2024-01-01T00:00:00")})
CREATE (l3:Location {city: "Beijing", postCode: "100000", country: "China", latitude: 39.9042, longitude: 116.4074, createdAt: datetime("2024-01-01T00:00:00")})
CREATE (l4:Location {city: "Lagos", postCode: "100001", country: "Nigeria", latitude: 6.5244, longitude: 3.3792, createdAt: datetime("2024-01-01T00:00:00")})
CREATE (l5:Location {city: "New York", postCode: "10001", country: "USA", latitude: 40.7128, longitude: -74.0060, createdAt: datetime("2024-01-01T00:00:00")})

//--------------------
// Create IP Addresses
//--------------------
CREATE (ip1:IP {ipAddress: "192.168.1.1", createdAt: datetime("2024-03-01T09:00:00")})
CREATE (ip2:IP {ipAddress: "10.0.0.1", createdAt: datetime("2024-03-01T10:00:00")})
CREATE (ip3:IP {ipAddress: "203.0.113.1", createdAt: datetime("2024-03-01T10:05:00")})
CREATE (ip4:IP {ipAddress: "198.51.100.1", createdAt: datetime("2024-03-01T11:00:00")})
CREATE (ip5:IP {ipAddress: "172.16.0.1", createdAt: datetime("2024-03-01T11:05:00")})

//--------------------
// Create Contact Information (Original)
//--------------------
CREATE (originalPhone:Phone {number: "447971020304", countryCode: "+44", createdAt: datetime("2024-01-01T00:00:00")})
CREATE (originalEmail:Email {address: "john@example.com", domain: "example.com", emailType: "personal", createdAt: datetime("2024-01-01T00:00:00")})
CREATE (originalAddr:Address {
    addressLine1: "123 High Street",
    addressLine2: "Flat 4B",
    postTown: "London",
    postCode: "SW1A 1AA",
    region: "Greater London",
    latitude: 51.5074,
    longitude: -0.1278,
    createdAt: datetime("2024-01-01T00:00:00")
})

//--------------------
// Create Contact Information (Changed by Attacker)
//--------------------
CREATE (newPhone:Phone {number: "447800123456", countryCode: "+44", createdAt: datetime("2024-03-01T14:35:00")})
CREATE (newEmail:Email {address: "attacker.new@protonmail.com", domain: "protonmail.com", emailType: "personal", createdAt: datetime("2024-03-01T14:40:00")})
CREATE (newAddr:Address {
    addressLine1: "999 Fraud Street",
    addressLine2: "Unit 13",
    postTown: "London",
    postCode: "E1 6XX",
    region: "Greater London",
    latitude: 51.5171,
    longitude: -0.0574,
    createdAt: datetime("2024-03-01T14:40:00")
})

//--------------------
// Create Accounts
//--------------------
CREATE (a1:Account:Internal {accountNumber: "ACC001", accountType: "CURRENT", openedDate: datetime("2024-01-01T00:00:00"), closedDate: null, suspendedDate: null})
CREATE (a2:Account:Internal {accountNumber: "ACC002", accountType: "CURRENT", openedDate: datetime("2024-01-01T00:00:00"), closedDate: null, suspendedDate: null})
CREATE (a3:Account:Internal {accountNumber: "ACC003", accountType: "CURRENT", openedDate: datetime("2024-01-01T00:00:00"), closedDate: null, suspendedDate: null})
CREATE (fraudAccount:Account:External:HighRiskJurisdiction {accountNumber: "FRAUD123456789", accountType: null, openedDate: null, closedDate: null, suspendedDate: null})

//--------------------
// Create Sessions (Normal, Failed, and ATO Session)
//--------------------
CREATE (s1:Session {sessionId: "SESS001", status: "success", createdAt: datetime("2024-03-01T14:30:00")})
CREATE (s2:Session {sessionId: "SESS002", status: "success", createdAt: datetime("2024-03-01T10:05:00")})
CREATE (s3:Session {sessionId: "SESS003", status: "failed", createdAt: datetime("2024-03-01T11:00:00")})
CREATE (s4:Session {sessionId: "SESS004", status: "failed", createdAt: datetime("2024-03-01T11:05:00")})
CREATE (s5:Session {sessionId: "SESS005", status: "failed", createdAt: datetime("2024-03-01T11:10:00")})

//--------------------
// Create Fraud Event Sequence (for Customer 1 - ATO Victim)
//--------------------
CREATE (e1:Authentication {method: "email", status: "success", createdAt: datetime("2024-03-01T14:30:00")})
CREATE (e2:ChangePhone {createdAt: datetime("2024-03-01T14:35:00")})
CREATE (e3:ChangeEmail {createdAt: datetime("2024-03-01T14:37:00")})
CREATE (e4:ChangeAddress {createdAt: datetime("2024-03-01T14:40:00")})
CREATE (e5:AddExternalAccount {createdAt: datetime("2024-03-01T14:50:00")})
CREATE (e6:Transfer {createdAt: datetime("2024-03-01T14:55:00")})

//--------------------
// Create Transaction (Fraudulent Transfer)
//--------------------
CREATE (fraudTransaction:Transaction {
    transactionId: "TXN_FRAUD_001",
    amount: 15000.00,
    currency: "GBP",
    date: datetime("2024-03-01T14:55:00"),
    message: "Emergency transfer",
    type: "SWIFT"
})

//--------------------
// Create Relationships: Countries
//--------------------
CREATE (l1)-[:LOCATED_IN]->(uk)
CREATE (l2)-[:LOCATED_IN]->(uk)
CREATE (l3)-[:LOCATED_IN]->(cn)
CREATE (l4)-[:LOCATED_IN]->(ng)
CREATE (l5)-[:LOCATED_IN]->(us)
CREATE (originalAddr)-[:LOCATED_IN]->(uk)
CREATE (newAddr)-[:LOCATED_IN]->(uk)
CREATE (a1)-[:IS_HOSTED]->(uk)
CREATE (a2)-[:IS_HOSTED]->(uk)
CREATE (a3)-[:IS_HOSTED]->(uk)
CREATE (fraudAccount)-[:IS_HOSTED]->(us)

//--------------------
// Create Relationships: Customer Identity
//--------------------
CREATE (c1)-[:HAS_PHONE {since: datetime("2024-03-01T14:35:00")}]->(newPhone)
CREATE (c1)-[:HAS_EMAIL {since: datetime("2024-03-01T14:37:00")}]->(newEmail)
CREATE (c1)-[:HAS_ADDRESS {addedAt: datetime("2024-03-01T14:40:00"), lastChangedAt: datetime("2024-03-01T14:40:00"), isCurrent: true}]->(newAddr)
CREATE (c1)-[:HAS_ACCOUNT {role: "owner", since: datetime("2024-01-01T00:00:00")}]->(a1)

CREATE (c2)-[:HAS_ACCOUNT {role: "owner", since: datetime("2024-01-01T00:00:00")}]->(a2)
CREATE (c3)-[:HAS_ACCOUNT {role: "owner", since: datetime("2024-01-01T00:00:00")}]->(a3)

//--------------------
// Create Relationships: Devices
//--------------------
CREATE (d1)-[:USED_BY {lastUsed: datetime("2024-03-01T09:00:00")}]->(c1)
CREATE (d2)-[:USED_BY {lastUsed: datetime("2024-03-01T09:30:00")}]->(c2)
// Pattern 1: Credential Stuffing - Single device accessing multiple accounts
CREATE (d3)-[:USED_BY {lastUsed: datetime("2024-03-01T10:00:00")}]->(c1)
CREATE (d3)-[:USED_BY {lastUsed: datetime("2024-03-01T10:02:00")}]->(c2)
CREATE (d3)-[:USED_BY {lastUsed: datetime("2024-03-01T10:04:00")}]->(c3)

//--------------------
// Create Relationships: Sessions to Customers
//--------------------
CREATE (c1)-[:HAS_SESSION]->(s1)
CREATE (c1)-[:HAS_SESSION]->(s2)
CREATE (c2)-[:HAS_SESSION]->(s3)
CREATE (c2)-[:HAS_SESSION]->(s4)
CREATE (c2)-[:HAS_SESSION]->(s5)

//--------------------
// Create Relationships: Sessions to Devices and IPs
//--------------------
CREATE (s1)-[:SESSION_USES_DEVICE]->(d1)
CREATE (s1)-[:USES_IP]->(ip1)

// Pattern 2: Impossible travel - UK to China in 5 minutes
CREATE (s2)-[:SESSION_USES_DEVICE]->(d3)
CREATE (s2)-[:USES_IP]->(ip3)

// Pattern 3: Multiple failed login attempts from different IPs and locations
CREATE (s3)-[:SESSION_USES_DEVICE]->(d2)
CREATE (s3)-[:USES_IP]->(ip2)
CREATE (s4)-[:SESSION_USES_DEVICE]->(d2)
CREATE (s4)-[:USES_IP]->(ip4)
CREATE (s5)-[:SESSION_USES_DEVICE]->(d2)
CREATE (s5)-[:USES_IP]->(ip5)

//--------------------
// Create Relationships: IPs to ISPs and Locations
//--------------------
CREATE (ip1)-[:IS_ALLOCATED_TO {createdAt: datetime("2024-01-01T00:00:00")}]->(isp1)
CREATE (ip1)-[:LOCATED_IN {createdAt: datetime("2024-03-01T09:00:00")}]->(l1)

CREATE (ip2)-[:IS_ALLOCATED_TO {createdAt: datetime("2024-01-01T00:00:00")}]->(isp2)
CREATE (ip2)-[:LOCATED_IN {createdAt: datetime("2024-03-01T10:00:00")}]->(l2)

CREATE (ip3)-[:IS_ALLOCATED_TO {createdAt: datetime("2024-01-01T00:00:00")}]->(isp4)
CREATE (ip3)-[:LOCATED_IN {createdAt: datetime("2024-03-01T10:05:00")}]->(l3)

CREATE (ip4)-[:IS_ALLOCATED_TO {createdAt: datetime("2024-01-01T00:00:00")}]->(isp3)
CREATE (ip4)-[:LOCATED_IN {createdAt: datetime("2024-03-01T11:00:00")}]->(l4)

CREATE (ip5)-[:IS_ALLOCATED_TO {createdAt: datetime("2024-01-01T00:00:00")}]->(isp3)
CREATE (ip5)-[:LOCATED_IN {createdAt: datetime("2024-03-01T11:05:00")}]->(l5)

//--------------------
// Create Relationships: Event Chain and Session Events
//--------------------
CREATE (e1)-[:NEXT]->(e2)-[:NEXT]->(e3)-[:NEXT]->(e4)-[:NEXT]->(e5)-[:NEXT]->(e6)
CREATE (s1)-[:HAS_AUTHENTICATION]->(e1)
CREATE (s1)-[:HAS_CHANGE_PHONE]->(e2)
CREATE (s1)-[:HAS_CHANGE_EMAIL]->(e3)
CREATE (s1)-[:HAS_CHANGE_ADDRESS]->(e4)
CREATE (s1)-[:HAS_ADD_EXTERNAL_ACCOUNT]->(e5)
CREATE (s1)-[:HAS_TRANSFER]->(e6)
CREATE (c1)-[:CONNECTS]->(e1)

//--------------------
// Create Relationships: Event Change Tracking (Old vs New)
//--------------------
CREATE (e2)-[:OLD_PHONE]->(originalPhone)
CREATE (e2)-[:NEW_PHONE]->(newPhone)
CREATE (e3)-[:OLD_EMAIL]->(originalEmail)
CREATE (e3)-[:NEW_EMAIL]->(newEmail)
CREATE (e4)-[:OLD_ADDRESS]->(originalAddr)
CREATE (e4)-[:NEW_ADDRESS]->(newAddr)

//--------------------
// Create Relationships: Account Addition and Transaction
//--------------------
CREATE (e5)-[:ADD_ACCOUNT]->(fraudAccount)
CREATE (e6)-[:HAS_TRANSACTION]->(fraudTransaction)
CREATE (a1)-[:PERFORMS]->(fraudTransaction)-[:BENEFITS_TO]->(fraudAccount)

演示数据中的关键欺诈模式

  1. 撞库(设备 DEV_SUSPICIOUS001):单个设备访问多个客户账户

  2. 不可能的旅行:5 分钟内在伦敦和北京先后发起会话

  3. 登录失败尝试:客户 2 从全球不同地点多次登录失败

  4. 事件速度:客户 1 - 所有账户更改均在 25 分钟内发生(14:30-14:55)

  5. 完整 ATO 生命周期:身份验证 → 电话/邮箱/地址更改 → 添加外部账户 → 15,000 英镑转账

  6. 取证线索:电话、邮箱和地址更改保留了旧值与新值的对比

4.3. Neo4j 架构

如果调用

// Show neo4j schema
CALL db.schema.visualization()

您将看到以下响应

fs account takeover fraud schema

5. Cypher 查询

5.1. 单个设备登录多个不同账户

在此查询中,我们将识别用于访问多个不同用户账户的设备,这是撞库攻击和账户接管尝试中的常见模式。

查看图谱

// Find all devices and the customers who use them MATCH (d:Device)-[:USED_BY]→(c:Customer)
MATCH (d:Device)-[:USED_BY]->(c:Customer)

// Count how many different customers use each device WITH d, count(DISTINCT c) as customerCount
WITH d, count(DISTINCT c) as customerCount

// Flag devices used by more than one customer WHERE customerCount > 1
WHERE customerCount > 1

// Retrieve the full network: device → customers → accounts MATCH path=(d)-[:USED_BY]→(c:Customer)-[:HAS_ACCOUNT]→(a:Account)
MATCH path=(d)-[:USED_BY]->(c:Customer)-[:HAS_ACCOUNT]->(a:Account)

// Return the suspicious pattern for investigation RETURN path
RETURN path

查看统计数据

// Get detailed statistics about devices accessing multiple accounts
MATCH (d:Device)-[:USED_BY]->(c:Customer)-[:HAS_ACCOUNT]->(a:Account)
WITH d,
     count(c) as uniqueAccounts,
     collect(c.customerId) as compromisedCustomers,
     d.deviceType as deviceType,
     d.userAgent as userAgent
WHERE uniqueAccounts > 1
RETURN d.deviceId as DeviceID,
       deviceType as DeviceType,
       userAgent as UserAgent,
       uniqueAccounts as NumberOfAccounts,
       compromisedCustomers as CompromisedCustomerIDs
ORDER BY uniqueAccounts DESC

它的作用

  • 第一个查询可视化了可疑设备网络及其与多个账户的连接

  • 第二个查询提供了每个可疑设备的详细统计信息,包括:

  • 访问的唯一账户数量

  • 设备类型和用户代理信息

  • 可能被泄露的电子邮件账户列表

风险指标

  • 24 小时内访问超过 2 个不同账户的设备

  • 跨多个账户的失败登录尝试

  • 可疑的用户代理字符串或设备特征

  • 提示自动化攻击的快速连续登录尝试

5.2. 可疑会话模式

在这些查询中,我们分析会话模式,通过异常的会话行为、失败的登录尝试以及会话内的可疑位置变更来识别潜在的账户接管尝试。

查看失败的登录尝试

// Show clusters of failed login attempts within a time window
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)
WHERE s.status = 'failed'
WITH c, s
ORDER BY s.createdAt
WITH c,
     collect({
         sessionId: s.sessionId,
         sessionTime: s.createdAt,
         status: s.status
     }) as attempts
WHERE size(attempts) >= 3
RETURN c.customerId as CustomerID,
       attempts,
       size(attempts) as FailedAttempts
ORDER BY FailedAttempts DESC

查看位置变更

// Detect rapid location changes within sessions (impossible travel)
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:USES_IP]->(ip:IP)-[:LOCATED_IN]->(l:Location)
WITH c, s, l
ORDER BY s.createdAt
WITH c,
     collect({
         location: l.city + ', ' + l.country,
         sessionTime: s.createdAt
     }) as locations
WHERE size(locations) > 1
RETURN c.customerId as CustomerID,
       locations,
       size(locations) as LocationChanges
ORDER BY LocationChanges DESC

查看会话时间轴

// Analyse session patterns over time
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:SESSION_USES_DEVICE]->(d:Device)
WITH c, d, s
RETURN c.customerId as CustomerID,
       d.deviceId as DeviceID,
       d.deviceType as DeviceType,
       s.createdAt as SessionTime,
       s.status as SessionStatus
ORDER BY s.createdAt

它的作用

  • 第一个查询识别失败的登录尝试簇

  • 按用户对失败尝试进行分组

  • 显示失败的序列和时间

  • 帮助识别暴力破解攻击

  • 第二个查询检测可疑的位置变更

  • 追踪用户会话内的位置变更

  • 识别物理上不可能的旅行模式

  • 帮助发现位置欺骗或受损账户

  • 第三个查询分析会话模式

  • 显示会话事件的完整时间轴

  • 追踪会话内的设备变更

  • 衡量会话持续时间和活动模式

风险指标

  • 短时间内多次失败的登录尝试

  • 登录地点的快速变更

  • 异常的会话持续时间或活动模式

  • 单个会话内使用了多个设备

  • 不匹配的设备类型或用户代理

  • 超出正常用户模式的会话

5.3. 来自不同 IP 的多次失败登录尝试

在这些查询中,我们分析针对同一账户的来自不同 IP 地址的失败登录尝试模式,这是暴力破解攻击的常见指标。

查看失败登录模式

// Show accounts with multiple failed login attempts from different IPs
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:USES_IP]->(ip:IP)
WHERE s.status = 'failed'
WITH c, count(DISTINCT ip) as uniqueIPs, collect(DISTINCT ip.ipAddress) as ipAddresses,
     count(s) as totalFailedAttempts
WHERE uniqueIPs >= 2
RETURN c.customerId as TargetCustomer,
       totalFailedAttempts as FailedAttempts,
       uniqueIPs as NumberOfUniqueIPs,
       ipAddresses as IPAddresses
ORDER BY totalFailedAttempts DESC

查看详细时间轴

// Show detailed timeline of failed attempts with location context
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:USES_IP]->(ip:IP),
      (ip)-[:LOCATED_IN]->(l:Location),
      (ip)-[:IS_ALLOCATED_TO]->(isp:ISP)
WHERE s.status = 'failed'
WITH c, count(DISTINCT ip) as uniqueIPs
WHERE uniqueIPs >= 2
MATCH (c)-[:HAS_SESSION]->(s:Session)-[:USES_IP]->(ip:IP),
      (ip)-[:LOCATED_IN]->(l:Location),
      (ip)-[:IS_ALLOCATED_TO]->(isp:ISP)
WHERE s.status = 'failed'
RETURN c.customerId as TargetCustomer,
       s.createdAt as AttemptTime,
       ip.ipAddress as IPAddress,
       l.city + ', ' + l.country as Location,
       isp.name as ISP
ORDER BY c.customerId, s.createdAt

查看地理分布

// Show geographic distribution of failed attempts
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:USES_IP]->(ip:IP)-[:LOCATED_IN]->(l:Location)
WHERE s.status = 'failed'
WITH c, l, count(s) as attemptsFromLocation
WITH c,
     count(DISTINCT l) as uniqueLocations,
     collect(DISTINCT {
         location: l.city + ', ' + l.country,
         attempts: attemptsFromLocation
     }) as locationBreakdown
WHERE uniqueLocations >= 2
RETURN c.customerId as TargetCustomer,
       uniqueLocations as NumberOfLocations,
       locationBreakdown as LocationBreakdown
ORDER BY uniqueLocations DESC

它的作用

  • 第一个查询概述了受攻击的账户

  • 统计每个账户的总失败次数

  • 显示使用的唯一 IP 数量

  • 列出涉及的所有 IP 地址

  • 第二个查询显示详细时间轴

  • 失败尝试的按时间顺序排列的序列

  • 每次尝试的地理位置

  • 每个 IP 的 ISP 信息

  • 帮助识别攻击模式和时间

  • 第三个查询分析地理分布

  • 显示唯一位置的数量

  • 提供每个位置的尝试细分

  • 帮助识别地理上分散的攻击

风险指标

  • 短时间内来自不同 IP 的多次失败尝试

  • 尝试之间地理上不可能的位置变更

  • 来自已知高风险 ISP 或位置的失败尝试

  • 提示自动化的系统性尝试时间模式

  • 大量唯一 IP 针对单个账户

5.4. 事件速度分析

使用时间顺序事件链检测快速的连续账户变更。此查询识别出多个关键账户修改在短时间内连续发生的各种可疑模式,这预示着自动化攻击。

检测快速事件序列

// Find sessions with rapid event sequences (multiple events within 30 minutes)
MATCH (c:Customer)-[:CONNECTS]->(firstEvent)
WHERE firstEvent:Authentication
MATCH path = (firstEvent)-[:NEXT*]->(lastEvent)
WITH c, firstEvent, lastEvent,
     duration.inSeconds(firstEvent.createdAt, lastEvent.createdAt).seconds AS durationSeconds,
     length(path) + 1 AS eventCount
WHERE durationSeconds <= 1800 AND eventCount >= 3
RETURN c.customerId AS CustomerID,
       firstEvent.createdAt AS FirstEventTime,
       lastEvent.createdAt AS LastEventTime,
       eventCount AS NumberOfEvents,
       durationSeconds / 60.0 AS DurationMinutes,
       eventCount / (durationSeconds / 60.0) AS EventsPerMinute
ORDER BY EventsPerMinute DESC

查看带有时间增量的事件时间轴

// Show detailed event timeline with time between consecutive events
MATCH (c:Customer)-[:CONNECTS]->(firstEvent:Authentication)
MATCH path = (firstEvent)-[:NEXT*0..]->(event)
WITH c, event,
     [(event)-[:NEXT]->(nextEvent) | duration.inSeconds(event.createdAt, nextEvent.createdAt).seconds][0] AS secondsToNext
ORDER BY event.createdAt
RETURN c.customerId AS CustomerID,
       labels(event) AS EventType,
       event.createdAt AS EventTime,
       secondsToNext AS SecondsToNextEvent,
       secondsToNext / 60.0 AS MinutesToNextEvent
ORDER BY c.customerId, EventTime

它的作用

  • 第一个查询识别具有异常快速事件序列的会话

  • 检测 30 分钟内发生 3 次以上事件

  • 计算总持续时间和事件速度

  • 按每分钟事件数排名(越高越可疑)

  • 第二个查询显示详细事件时间轴

  • 按时间顺序列出所有事件

  • 显示连续事件之间的时间间隔

  • 识别暗示自动化的异常短间隔

风险指标

  • 15 分钟内发生超过 3 个事件

  • 事件速度超过每 5 分钟 1 个事件

  • 暗示自动化脚本的一致性时间间隔

  • 所有联系信息更改在单个会话内完成

5.5. 账户接管生命周期检测

识别从身份验证到资金转账的完整 ATO 攻击模式。这可以检测到经典的账户接管序列:未经授权的访问 → 联系方式更改 → 添加外部账户 → 欺诈性转账。

检测完整 ATO 模式

// Find complete account takeover sequences ending in transfers
MATCH (c:Customer)-[:CONNECTS]->(auth:Authentication)
WHERE auth.status = "success"
WITH c, auth
MATCH (auth)-[:NEXT*1..10]->(changeEvent)
WHERE changeEvent:ChangePhone OR changeEvent:ChangeEmail OR changeEvent:ChangeAddress
WITH c, auth, changeEvent
MATCH (changeEvent)-[:NEXT*1..5]->(add:AddExternalAccount)
WITH c, auth, add
MATCH (add)-[:NEXT*1..3]->(transfer:Transfer)-[:HAS_TRANSACTION]->(t:Transaction)
RETURN DISTINCT c.customerId AS VictimCustomer,
       auth.createdAt AS InitialAccessTime,
       transfer.createdAt AS FraudTransferTime,
       t.amount AS TransferAmount,
       t.currency AS Currency,
       duration.inSeconds(auth.createdAt, transfer.createdAt).seconds / 60.0 AS MinutesFromAccessToTransfer
ORDER BY TransferAmount DESC

查看完整攻击链

// Show complete event chain for suspected account takeover
MATCH (c:Customer)-[:CONNECTS]->(auth:Authentication)
MATCH path = (auth)-[:NEXT*]->(finalEvent)
WHERE finalEvent:Transfer
WITH c, auth, path, finalEvent
MATCH (finalEvent)-[:HAS_TRANSACTION]->(t:Transaction)-[:BENEFITS_TO]->(externalAccount:Account:External)
UNWIND nodes(path) AS event
RETURN c.customerId AS CustomerID,
       labels(event) AS EventType,
       event.createdAt AS EventTime,
       t.amount AS FraudAmount,
       externalAccount.accountNumber AS DestinationAccount
ORDER BY c.customerId, EventTime

它的作用

  • 第一个查询检测完整 ATO 生命周期

  • 以成功的身份验证开始

  • 包含联系信息更改

  • 显示外部账户添加

  • 以欺诈性转账结束

  • 计算攻击持续时间

  • 第二个查询显示完整攻击链

  • 列出序列中的每个事件

  • 识别最终目的地账户

  • 显示总欺诈金额

  • 提供完整取证时间轴

风险指标

  • 60 分钟内完成攻击链

  • 大额转账(>10,000 英镑)

  • 向高风险司法管辖区的转账

  • 转账前多次更改联系信息

  • 新外部账户添加后紧随转账

5.6. 变更历史分析

追踪旧值与新值以进行取证调查。这使欺诈分析师能够清楚地看到账户接管期间发生了哪些变动,从而为调查和客户恢复提供关键证据。

查看电话号码变更

// Show phone number changes with old and new values
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:HAS_CHANGE_PHONE]->(change:ChangePhone)
MATCH (change)-[:OLD_PHONE]->(oldPhone:Phone)
MATCH (change)-[:NEW_PHONE]->(newPhone:Phone)
RETURN c.customerId AS CustomerID,
       change.createdAt AS ChangeTime,
       oldPhone.number AS OldPhoneNumber,
       newPhone.number AS NewPhoneNumber,
       s.sessionId AS SessionID
ORDER BY change.createdAt DESC

查看邮箱变更

// Show email address changes with old and new values
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:HAS_CHANGE_EMAIL]->(change:ChangeEmail)
MATCH (change)-[:OLD_EMAIL]->(oldEmail:Email)
MATCH (change)-[:NEW_EMAIL]->(newEmail:Email)
RETURN c.customerId AS CustomerID,
       change.createdAt AS ChangeTime,
       oldEmail.address AS OldEmailAddress,
       newEmail.address AS NewEmailAddress,
       newEmail.domain AS NewEmailDomain,
       s.sessionId AS SessionID
ORDER BY change.createdAt DESC

查看地址变更

// Show address changes with old and new values
MATCH (c:Customer)-[:HAS_SESSION]->(s:Session)-[:HAS_CHANGE_ADDRESS]->(change:ChangeAddress)
MATCH (change)-[:OLD_ADDRESS]->(oldAddr:Address)
MATCH (change)-[:NEW_ADDRESS]->(newAddr:Address)
RETURN c.customerId AS CustomerID,
       change.createdAt AS ChangeTime,
       oldAddr.addressLine1 + ', ' + oldAddr.postTown + ' ' + oldAddr.postCode AS OldAddress,
       newAddr.addressLine1 + ', ' + newAddr.postTown + ' ' + newAddr.postCode AS NewAddress,
       s.sessionId AS SessionID
ORDER BY change.createdAt DESC

查看客户的所有变更

// Show complete change history for a specific customer
MATCH (c:Customer {customerId: "CUS001"})-[:HAS_SESSION]->(s:Session)
OPTIONAL MATCH (s)-[:HAS_CHANGE_PHONE]->(phoneChange:ChangePhone)
OPTIONAL MATCH (phoneChange)-[:OLD_PHONE]->(oldPhone:Phone)
OPTIONAL MATCH (phoneChange)-[:NEW_PHONE]->(newPhone:Phone)
OPTIONAL MATCH (s)-[:HAS_CHANGE_EMAIL]->(emailChange:ChangeEmail)
OPTIONAL MATCH (emailChange)-[:OLD_EMAIL]->(oldEmail:Email)
OPTIONAL MATCH (emailChange)-[:NEW_EMAIL]->(newEmail:Email)
OPTIONAL MATCH (s)-[:HAS_CHANGE_ADDRESS]->(addrChange:ChangeAddress)
OPTIONAL MATCH (addrChange)-[:OLD_ADDRESS]->(oldAddr:Address)
OPTIONAL MATCH (addrChange)-[:NEW_ADDRESS]->(newAddr:Address)
RETURN c.customerId AS CustomerID,
       coalesce(phoneChange.createdAt, emailChange.createdAt, addrChange.createdAt) AS ChangeTime,
       CASE
         WHEN phoneChange IS NOT NULL THEN 'Phone'
         WHEN emailChange IS NOT NULL THEN 'Email'
         WHEN addrChange IS NOT NULL THEN 'Address'
       END AS ChangeType,
       oldPhone.number AS OldPhone,
       newPhone.number AS NewPhone,
       oldEmail.address AS OldEmail,
       newEmail.address AS NewEmail,
       oldAddr.addressLine1 AS OldAddress,
       newAddr.addressLine1 AS NewAddress
ORDER BY ChangeTime

它的作用

  • 前三个查询显示特定变更类型

  • 带有更改前/更改后值的电话号码修改

  • 包括新域名的电子邮件地址变更

  • 包含完整详细信息的物理地址更新

  • 第四个查询提供统一视图

  • 按时间顺序列出客户的所有变更

  • 变更类型识别(电话、邮箱、地址)

  • 每次变更的前后值

  • 用于审计目的的会话追踪

用例

  • 受损账户的取证调查

  • 欺诈后的客户账户恢复

  • 跨多个受害者的欺诈模式分析

  • 法规遵从和审计追踪

  • 为执法部门收集证据

© . This site is unofficial and not affiliated with Neo4j, Inc.