地铁吐血女孩最讨厌蹭吃蹭喝的人,聊聊跨境代购系统的风控与防薅羊毛实战
看到"地铁吐血女孩:最讨厌来蹭吃蹭喝的人"这条热搜,我太有共鸣了。
做跨境电商的,谁没被薅过羊毛?有的人真的是,什么便宜都想占,优惠券反复领、退款骗货、恶意差评威胁,什么招都有。
今天就聊聊代购系统的风控和防薅羊毛。这玩意儿,说多了都是泪。
我见过的各种薅羊毛手段
做这行几年,我见过的薅羊毛手段,能写一本书。
第一种:优惠券薅羊毛
这个最常见。有人注册几十个账号,每个账号领新人优惠券,然后下单,地址都一样。你要是没发现,他就赚了;你要是发现了,大不了退款,他也没损失。
第二种:退款骗货
更恶心的是这种。收到货了,说没收到,或者说货坏了,要求退款。你要是不同意,他就去支付平台申诉,PayPal什么的,一般都偏向买家。很多时候卖家只能吃哑巴亏。
第三种:恶意下单
竞争对手搞你,用一堆小号疯狂下单,然后全部取消。你采购了吧,他退了,货砸手里;你不采购吧,他投诉你虚假发货。
第四种:运费差价
这个更隐蔽。比如你系统里运费算错了,或者某个渠道有漏洞,有人就专门找这种漏洞下单,一次能省好几百运费。
还有更绝的,我就不一一列举了。总之,只有你想不到,没有他们做不到。
风控系统该怎么设计?
防薅羊毛,不能靠人工,必须靠系统。
我一般会从这几个层面做风控:
用户层面
注册的时候就要风控:手机号是不是虚拟号?IP地址是不是异常?设备有没有问题?
订单层面
下单的时候风控:收货地址是不是高风险地址?下单频率是不是太高?金额是不是异常?
行为层面
用户的操作行为:是不是秒下单?是不是只买最便宜的?是不是反复取消订单?
支付层面
支付的时候风控:是不是常用的支付方式?是不是异地支付?信用卡是不是高风险的?
简单的风控规则引擎示例
实际项目中建议用 Drools 之类的规则引擎,或者自己写个更完善的
from enum import Enum
from typing import List, Dict
class RiskLevel(Enum):
LOW = "low" # 低风险,直接通过
MEDIUM = "medium" # 中风险,需要人工审核
HIGH = "high" # 高风险,直接拒绝
class RiskRule:
"""风控规则"""
def init(self, name: str, weight: int, check_func):
self.name = name
self.weight = weight
self.check_func = check_func
class RiskEngine:
"""
简单的风控引擎
踩坑:
1. 规则不是越多越好,要根据实际情况调整
2. 误杀率很重要,不能为了防薅羊毛把正常用户也挡了
3. 规则要能动态调整,不能写死在代码里
"""
def init(self):
self.rules: List[RiskRule] = []
def add_rule(self, rule: RiskRule):
self.rules.append(rule)
def evaluate(self, context: Dict) -> RiskLevel:
"""评估风险等级"""
total_score = 0
hit_rules = []
for rule in self.rules:
if rule.check_func(context):
total_score += rule.weight
hit_rules.append(rule.name)
if total_score >= 80:
return RiskLevel.HIGH, hit_rules
elif total_score >= 40:
return RiskLevel.MEDIUM, hit_rules
else:
return RiskLevel.LOW, hit_rules
定义一些规则
rules = [
RiskRule("新用户+大金额订单", 30,
lambda ctx: ctx.get("is_new_user") and ctx.get("order_amount") > 500),
RiskRule("短时间内多次下单", 40,
lambda ctx: ctx.get("order_count_1h", 0) > 5),
RiskRule("收货地址是高风险地区", 50,
lambda ctx: ctx.get("address_risk") == "high"),
RiskRule("使用虚拟手机号", 60,
lambda ctx: ctx.get("is_virtual_phone")),
RiskRule("IP地址异常", 35,
lambda ctx: ctx.get("ip_risk") == "high"),
]
用法
engine = RiskEngine()
for rule in rules:
engine.add_rule(rule)
context = {
"is_new_user": True,
"order_amount": 800,
"order_count_1h": 3,
"address_risk": "low",
"is_virtual_phone": False,
"ip_risk": "low",
}
risk_level, hit_rules = engine.evaluate(context)
print(f"风险等级: {risk_level.value}")
print(f"命中规则: {hit_rules}")
几个重点风控场景
注册风控
很多薅羊毛的都是批量注册账号,所以注册环节的风控很重要。
手机号验证:必须短信验证,而且要检测是不是虚拟号。现在有很多第三方接口可以查手机号运营商类型。
IP限制:同一个IP短时间内不能注册太多账号。
设备指纹:这个更高级一点,通过设备信息识别是不是同一台设备。就算换号换IP,设备没变,也能识别出来。
2. 优惠券风控
优惠券是重灾区,必须重点防。
限制领取次数:同一个用户、同一个手机号、同一个设备,只能领一次。
使用限制:优惠券不能叠加,有最低消费,指定商品才能用。
异常检测:如果某个优惠券突然被大量使用,而且都是新用户,那肯定有问题。
3. 退款风控
退款这块,水更深。
退款率监控:某个用户退款率太高,就要重点关注。
收货地址分析:如果一个地址经常退款,那可能是职业打假的。
退款原因分析:总是说没收到货?总是说商品有问题?这些都要标记。
用户风险画像示例
把用户的各种行为数据汇总,给用户打风险分
def calculate_user_risk_score(user_id):
"""
计算用户风险分
分数越高,风险越大
"""
score = 0
基础信息
user = User.objects.get(id=user_id)
if user.is_virtual_phone:
score += 20
if user.register_ip_risk == "high":
score += 15
订单行为
order_stats = get_user_order_stats(user_id)
total_orders = order_stats["total"]
refund_rate = order_stats["refund_count"] / total_orders if total_orders > 0 else 0
if refund_rate > 0.5:
score += 40
elif refund_rate > 0.3:
score += 25
取消率
cancel_rate = order_stats["cancel_count"] / total_orders if total_orders > 0 else 0
if cancel_rate > 0.6:
score += 30
elif cancel_rate > 0.4:
score += 15
收货地址数量(地址太多可能有问题)
address_count = get_user_address_count(user_id)
if address_count > 10:
score += 20
elif address_count > 5:
score += 10
return score
风控的度怎么把握?
这是个老大难问题。
风控太松,薅羊毛的防不住;风控太紧,正常用户也被挡了,影响转化。
我觉得关键是分层处理:
低风险:直接通过,啥也不用管
中风险:可以下单,但要人工审核,或者限制一些功能
高风险:直接拒绝,或者需要额外验证
而且规则要不断调整。道高一尺魔高一丈,薅羊毛的手段一直在变,你的风控规则也要跟着变。
最后说两句
防薅羊毛这事儿,是一场持久战。你永远不可能完全杜绝,只能尽量降低损失。
taocarts的代购系统在风控这块做得就挺完善的,各种规则都有,还能根据数据自动调整。人家做了这么多年,见过的套路多了去了。
当然了,系统只是一方面,运营也很重要。要有人专门盯着数据,发现异常及时处理。
今天就聊到这儿。你们做电商的,有没有被薅过羊毛?有什么防薅的好办法?评论区交流交流。