账户盗用欺诈
1. 简介
账户盗用欺诈 (ATO) 是一种复杂的身份盗窃形式,网络犯罪分子通过这种方式未经授权地访问合法用户账户。这种日益增长的威胁影响着从金融服务到社交媒体平台等各种账户类型,对个人和组织都造成了重大影响。根据最近的研究,22% 的美国成年人曾是 ATO 欺诈的受害者,平均个人损失高达 12,000 美元。这种欺诈通常涉及通过网络钓鱼、数据泄露或社会工程等方式窃取凭证,然后利用账户进行未经授权的交易或进一步的欺诈活动。随着数字服务的扩展,强大的检测和预防策略对于防范这种不断演变的威胁变得越来越重要。
2. 场景
问题范围
-
广泛影响:22% 的美国成年人曾是账户盗用的受害者
-
财务损失:每次事件的平均个人损失达 12,000 美元
-
业务影响:严重的声誉损害和潜在的法律后果
-
复杂性增加:越来越多地使用自动化工具和 AI 进行大规模攻击
挑战
-
复杂的攻击向量:通过网络钓鱼、恶意软件和社会工程的多个入口点
-
凭证填充:使用被盗用户名/密码组合的自动化攻击
-
设备欺骗:欺诈者使用先进技术绕过设备指纹识别
-
身份验证绕过:规避多因素身份验证的复杂方法
3. 解决方案
图数据库为检测和预防账户盗用欺诈提供了一种强大的方法。通过将用户行为、设备交互和账户活动的复杂网络建模为互联网络,图技术可以识别传统系统可能遗漏的可疑模式。这种方法对于 ATO 欺诈特别有效,因为它需要同时分析多个数据点和关系。
3.1. 图数据库如何提供帮助?
-
设备指纹识别: Neo4j 可以跟踪用户账户、设备和 IP 地址之间的关系,以识别可疑的登录模式和潜在的凭证填充攻击。
-
行为分析: 图数据库擅长建模正常用户行为模式并检测异常,例如
-
异常登录时间或地点
-
交易模式的可疑变化
-
意外的账户设置修改
-
应用程序内的异常导航模式
-
-
身份验证网络: 创建连接以下各项的综合身份图
-
用户账户和相关的电子邮件地址
-
电话号码和身份验证方法
-
设备指纹和登录位置
-
交易模式和受益人关系
-
-
实时检测: Neo4j 支持
-
根据已知模式即时验证登录尝试
-
实时分析交易序列
-
即时识别可疑 IP 地址或设备
-
基于图模式的动态风险评分
-
-
网络分析: 通过以下方式揭露复杂的欺诈团伙
-
识别被盗账户之间的共享属性
-
检测可疑活动集群
-
追踪凭证填充攻击的蔓延
-
映射已知欺诈实体之间的关系
-
4. 建模
本节提供 Cypher 查询示例,演示如何构建数据以检测账户盗用欺诈。示例图将包括用户、设备、会话、位置和身份验证事件的节点,以及显示这些实体在正常和可疑账户访问模式下如何交互的关系。
4.1. 数据模型
4.1.1 必填字段
Person
节点
-
id
: 人员的唯一标识符 -
email
: 主要电子邮件地址
Device
节点
-
deviceID
: 设备的唯一标识符 -
deviceType
: 设备类型(移动设备、桌面设备、平板电脑) -
userAgent
: 浏览器/应用用户代理字符串
IP
节点
-
ip
: IP 地址
ISP
节点
-
isp
: 互联网服务提供商
Location
节点
-
city
: 城市名称 -
country
: 国家代码
Session
节点
-
sessionID
: 唯一会话标识符 -
status
: 会话状态(成功、失败、可疑)
Event
节点
-
eventID
: 唯一事件标识符 -
eventType
: 身份验证事件类型 -
timestamp
: 事件时间戳 -
status
: 身份验证状态
Account
节点
-
accountNumber
: 唯一账户号码
关系
-
USED_BY
: 人员使用设备 -
PARTICIPATED_IN_EVENT
: 人员参与事件 -
USES_IP
: 事件使用 IP -
HAS_LOCATION
: 事件具有位置 -
SESSION_USES_DEVICE
: 会话使用设备 -
OWNS
: 人员拥有账户 -
IS_ALLOCATED_TO
: IP 分配给 ISP -
LOCATED_IN
: IP 位于位置 -
HAS_EVENT
: 会话具有事件
4.2. 演示数据
以下 Cypher 语句将创建一个示例图,演示典型的账户访问模式
//
// Create Person nodes
//
CREATE (p1:Person {id: "P001", email: "user1@example.com"})
CREATE (p2:Person {id: "P002", email: "user2@example.com"})
CREATE (p3:Person { id: "P003", email: "user3@example.com"})
//
// Create Device nodes
//
CREATE (d1:Device {id: "WEB001", deviceType: "desktop", userAgent: "Mozilla/5.0 Chrome/91.0"})
CREATE (d2:Device {id: "WEB002", deviceType: "mobile", userAgent: "Mozilla/5.0 Mobile Safari/537.36"})
CREATE (d3:Device {id: "SUSPICIOUS001", deviceType: "desktop", userAgent: "Mozilla/5.0 Firefox/89.0"})
//
// Create IP nodes
//
CREATE (ip1:IP {ip: "192.168.1.1"})
CREATE (ip2:IP {ip: "10.0.0.1"})
CREATE (ip3:IP {ip: "203.0.113.1"})
CREATE (ip4:IP {ip: "198.51.100.1"})
CREATE (ip5:IP {ip: "172.16.0.1"})
//
// Create ISP nodes
//
CREATE (isp1:ISP {isp: "BT"})
CREATE (isp2:ISP {isp: "Orange"})
CREATE (isp3:ISP {isp: "Verizon"})
CREATE (isp4:ISP {isp: "China Telecom"})
//
// Create Location nodes
//
CREATE (l1:Location {city: "London", country: "UK"})
CREATE (l2:Location {city: "Paris", country: "France"})
CREATE (l3:Location {city: "Beijing", country: "China"})
CREATE (l4:Location {city: "Lagos", country: "Nigeria"})
CREATE (l5:Location {city: "New York", country: "USA"})
//
// Create Session nodes
//
CREATE (s1:Session {id: "SESS001", status: "success"})
CREATE (s2:Session {id: "SESS002", status: "success"})
CREATE (s3:Session {id: "SESS003", status: "failed"})
CREATE (s4:Session {id: "SESS004", status: "failed"})
CREATE (s5:Session {id: "SESS005", status: "failed"})
//
// Create Event nodes
//
CREATE (e1:Event {created: datetime("2024-03-01T10:00:00"), id: "EVT001", sessionKey: "SESS001", status: "success"})
CREATE (e2:Event {created: datetime("2024-03-01T10:05:00"), id: "EVT002", sessionKey: "SESS002", status: "success"})
CREATE (e3:Event {created: datetime("2024-03-01T11:00:00"), id: "EVT003", sessionKey: "SESS003", status: "failed"})
CREATE (e4:Event {created: datetime("2024-03-01T11:05:00"), id: "EVT004", sessionKey: "SESS004", status: "failed"})
CREATE (e5:Event {created: datetime("2024-03-01T11:10:00"), id: "EVT005", sessionKey: "SESS005", status: "failed"})
//
// Create Account nodes
//
CREATE (a1:Account {accountNumber: "ACC001"})
CREATE (a2:Account {accountNumber: "ACC002"})
CREATE (a3:Account {accountNumber: "ACC003"})
//
// Create Relationships
//
// Pattern 1: Single device logging into multiple accounts
CREATE (d3)-[:USED_BY]->(p1)
CREATE (d3)-[:USED_BY]->(p2)
CREATE (d3)-[:USED_BY]->(p3)
// Pattern 2: Different locations logging into single account
CREATE (p1)-[:PARTICIPATED_IN_EVENT]->(e1)
CREATE (e1)-[:USES_IP]->(ip1)
CREATE (e1)-[:HAS_LOCATION]->(l1)
CREATE (p1)-[:PARTICIPATED_IN_EVENT]->(e2)
CREATE (e2)-[:USES_IP]->(ip3)
CREATE (e2)-[:HAS_LOCATION]->(l3)
// Pattern 3: Multiple failed login attempts from different IPs
CREATE (p2)-[:PARTICIPATED_IN_EVENT]->(e3)
CREATE (e3)-[:USES_IP]->(ip2)
CREATE (e3)-[:HAS_LOCATION]->(l2)
CREATE (p2)-[:PARTICIPATED_IN_EVENT]->(e4)
CREATE (e4)-[:USES_IP]->(ip4)
CREATE (e4)-[:HAS_LOCATION]->(l4)
CREATE (p2)-[:PARTICIPATED_IN_EVENT]->(e5)
CREATE (e5)-[:USES_IP]->(ip5)
CREATE (e5)-[:HAS_LOCATION]->(l5)
// Additional contextual relationships
CREATE (ip1)-[:IS_ALLOCATED_TO]->(isp1)
CREATE (ip2)-[:IS_ALLOCATED_TO]->(isp2)
CREATE (ip3)-[:IS_ALLOCATED_TO]->(isp4)
CREATE (ip4)-[:IS_ALLOCATED_TO]->(isp3)
CREATE (ip5)-[:IS_ALLOCATED_TO]->(isp3)
// Connect IP to Location
CREATE (ip1)-[:LOCATED_IN]->(l1)
CREATE (ip2)-[:LOCATED_IN]->(l2)
CREATE (ip3)-[:LOCATED_IN]->(l3)
CREATE (ip4)-[:LOCATED_IN]->(l4)
CREATE (ip5)-[:LOCATED_IN]->(l5)
// Session device relationships
CREATE (s1)-[:SESSION_USES_DEVICE]->(d1)
CREATE (s2)-[:SESSION_USES_DEVICE]->(d3)
CREATE (s3)-[:SESSION_USES_DEVICE]->(d2)
CREATE (s4)-[:SESSION_USES_DEVICE]->(d2)
CREATE (s5)-[:SESSION_USES_DEVICE]->(d2)
// Connect Session to Event
CREATE (s1)-[:HAS_EVENT]->(e1)
CREATE (s2)-[:HAS_EVENT]->(e2)
CREATE (s3)-[:HAS_EVENT]->(e3)
CREATE (s4)-[:HAS_EVENT]->(e4)
CREATE (s5)-[:HAS_EVENT]->(e5)
// Update Relationships
CREATE (p1)-[:OWNS]->(a1)
CREATE (p2)-[:OWNS]->(a2)
CREATE (p3)-[:OWNS]->(a3)
5. Cypher 查询
5.1. 单个设备登录到多个不同账户
在此查询中,我们将识别用于访问多个不同用户账户的设备,这是凭证填充攻击和账户盗用尝试中的常见模式。
查看图
// Show the relationships between suspicious devices and multiple accounts
MATCH path=(d:Device)-[:USED_BY]->(p:Person)-[:OWNS]->(a:Account)
WITH d, count(p) as accountCount
WHERE accountCount > 1
MATCH path=(d)-[:USED_BY]->(p:Person)-[:OWNS]->(a:Account)
RETURN path
查看统计数据
// Get detailed statistics about devices accessing multiple accounts
MATCH (d:Device)-[:USED_BY]->(p:Person)-[:OWNS]->(a:Account)
WITH d,
count(p) as uniqueAccounts,
collect(p.email) as compromisedEmails,
d.deviceType as deviceType,
d.userAgent as userAgent
WHERE uniqueAccounts > 1
RETURN d.id as DeviceID,
deviceType as DeviceType,
userAgent as UserAgent,
uniqueAccounts as NumberOfAccounts,
compromisedEmails as CompromisedAccounts
ORDER BY uniqueAccounts DESC
5.2. 可疑会话模式
在这些查询中,我们分析会话模式,通过异常会话行为、登录失败尝试和会话内可疑位置变化来识别潜在的账户盗用尝试。
查看登录失败尝试
// Show clusters of failed login attempts within a time window
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event)
WHERE e.status = 'failed'
WITH p, e
ORDER BY e.created
WITH p,
collect({
eventId: e.id,
eventTime: e.created,
status: e.status
}) as attempts
WHERE size(attempts) >= 3
RETURN p.email as UserEmail,
attempts,
size(attempts) as FailedAttempts
ORDER BY FailedAttempts DESC
查看位置变化
// Detect rapid location changes within sessions
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event)-[:HAS_LOCATION]->(l:Location)
WITH p, e, l
ORDER BY e.created
WITH p,
collect({
location: l.city + ', ' + l.country,
eventTime: e.created
}) as locations
WHERE size(locations) > 1
RETURN p.email as UserEmail,
locations,
size(locations) as LocationChanges
ORDER BY LocationChanges DESC
查看会话时间轴
// Analyse session patterns over time
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event), (d:Device)<-[:SESSION_USES_DEVICE]-(s:Session)-[:HAS_EVENT]->(e:Event)
WHERE e.sessionKey = s.id
WITH p, d, e, s
RETURN p.email as UserEmail,
d.id as DeviceID,
d.deviceType as DeviceType,
e.created as EventTime,
s.status as SessionStatus,
duration.between(
min(e.created),
max(e.created)
).minutes as SessionDurationMinutes
ORDER BY e.created
5.3. 来自不同 IP 的多次登录失败尝试
在这些查询中,我们分析来自不同 IP 地址针对同一账户的登录失败尝试模式,这是暴力破解攻击的常见指标。
查看登录失败模式
// Show accounts with multiple failed login attempts from different IPs
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event)-[:USES_IP]->(ip:IP)
WHERE e.status = 'failed'
WITH p, count(DISTINCT ip) as uniqueIPs, collect(DISTINCT ip.ip) as ipAddresses,
count(e) as totalFailedAttempts
WHERE uniqueIPs >= 2
RETURN p.email as TargetAccount,
totalFailedAttempts as FailedAttempts,
uniqueIPs as NumberOfUniqueIPs,
ipAddresses as IPAddresses
ORDER BY totalFailedAttempts DESC
查看详细时间轴
// Show detailed timeline of failed attempts with location context
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event)-[:USES_IP]->(ip:IP),
(e)-[:HAS_LOCATION]->(l:Location),
(ip)-[:IS_ALLOCATED_TO]->(isp:ISP)
WHERE e.status = 'failed'
WITH p, count(DISTINCT ip) as uniqueIPs
WHERE uniqueIPs >= 2
MATCH (p)-[:PARTICIPATED_IN_EVENT]->(e:Event)-[:USES_IP]->(ip:IP),
(e)-[:HAS_LOCATION]->(l:Location),
(ip)-[:IS_ALLOCATED_TO]->(isp:ISP)
WHERE e.status = 'failed'
RETURN p.email as TargetAccount,
e.created as AttemptTime,
ip.ip as IPAddress,
l.city + ', ' + l.country as Location,
isp.isp as ISP
ORDER BY p.email, e.created
查看地理分布
// Show geographic distribution of failed attempts
MATCH (p:Person)-[:PARTICIPATED_IN_EVENT]->(e:Event)-[:HAS_LOCATION]->(l:Location)
WHERE e.status = 'failed'
WITH p, l, count(e) as attemptsFromLocation
WITH p,
count(DISTINCT l) as uniqueLocations,
collect(DISTINCT {
location: l.city + ', ' + l.country,
attempts: attemptsFromLocation
}) as locationBreakdown
WHERE uniqueLocations >= 2
RETURN p.email as TargetAccount,
uniqueLocations as NumberOfLocations,
locationBreakdown as LocationBreakdown
ORDER BY uniqueLocations DESC