营销反作弊接入
2020.06.09 13:57:51
接口通用参数
请求公共参数
易盾营销反作弊服务的所有接口均包含这些公共参数。
参数名称 | 类型 | 必须 | 最大长度 | 描述 |
---|---|---|---|---|
version | String | 是 | 4 | 接口版本号,当前可用版本为200 |
secretId | String | 是 | 32 | 秘钥id ,由营销反作弊服务分配 |
businessId | String | 是 | 32 | 业务id,由营销反作弊服务分配 |
timestamp | Long | 是 | 10 | 当前 UNIX 时间戳,单位:秒。 |
nonce | String | 是 | 32 | 随机字符串,与 timestamp 联合起来,用于防止重放攻击 |
signature | String | 是 | 32 | 请求签名,用来验证此次请求的合法性。签名过程和算法参见:签名生成算法。请注意:请将签名转换成小写。 |
通用响应结果
所有接口响应均采用json格式,如无特殊说明,每次请求的返回值都包含如下字段:
参数名称 | 类型 | 描述 |
---|---|---|
code | int | 接口调用状态,取值参见:响应返回码。 |
msg | String | 结果说明,如果调用出错,返回错误描述 |
result | Object | 接口返回结果,具体参见各接口说明。 |
响应返回码
返回码 | 返回码描述 | 说明 |
---|---|---|
200 | ok | 接口调用状态。 |
400 | bad request | 请求参数错误 |
401 | forbidden | 没权限使用此接口 |
405 | param error | 参数错误 |
410 | signature failure | 签名验证失败 |
420 | request expired | 请求时间戳不正确 |
430 | replay attack | 重放请求 |
440 | decode error | 参数解密失败 |
450 | wrong token | 查询token错误 |
503 | service unavailable | 服务器内部出现异常 |
接口鉴权
- 申请安全凭证
在第一次使用 API 之前,需申请安全凭证,安全凭证包括 SecretId 和 SecretKey ,SecretId 是用于标识 API 调用者的身份,SecretKey 是用于加密签名字符串和服务器端验证签名字符串的密钥。SecretKey 必须严格保管,避免泄露。
- 签名生成算法
签名过程:
- 参数排序:对所有请求参数(不包括 signature 参数),按照参数名ASCII码表升序顺序排序。如:foo=1, bar=2, foo_bar=3, baz=4 排序后的顺序是 bar=2, baz=4, foo=1, foobar=3 。
- 拼接参数:将排序好的参数名和参数值构造成字符串,格式为:key1+value1+key2+value2… 。根据上面的示例得到的构造结果为:bar2baz4foo1foobar3。
- 拼接KEY:选择与 secretId 配对的 secretKey ,加到上一步构造好的参数字符串之后,如 secretKey=6308afb129ea00301bd7c79621d07591 ,则最后的参数字符串为 bar2baz4foo1foobar36308afb129ea00301bd7c79621d07591 。
- 签名HASH:把上一步骤拼装好的字符串采用 utf-8 编码,使用 MD5 算法对字符串进行摘要,计算得到 signature 参数值,将其加入到接口请求参数中即可。MD5 是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32位十六进制字符。
示例代码
/**
* 生成签名信息
* @param secretKey 产品私钥
* @param params 接口请求参数名和参数值map,不包括signature参数名
* @return
*/
public static String genSignature(String secretKey, Map<String, String> params) {
if (secretKey == null || params == null || params.size() == 0) {
return "";
}
// 1. 参数名按照ASCII码表升序排序
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
// 2. 按照排序拼接参数名与参数值
StringBuffer paramBuffer = new StringBuffer();
for (String key : keys) {
paramBuffer.append(key).append(params.get(key) == null ? "" : params.get(key));
}
// 3. 将secretKey拼接到最后
paramBuffer.append(secretKey);
// 4. MD5是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32个十六进制字符。
return DigestUtils.md5Hex(paramBuffer.toString().getBytes("UTF-8"));
}
营销反作弊check接口
- 接口地址:http://ac.dun.163.com/v2/activity/check
- 请求方法:POST
- 接口说明:营销反作弊检测
- 注意事项:建议设置http请求的超时时间,且建议http超时的情况下,认为检测结果为 “正常”。
请求参数
公共参数已省略,详细见:请求公共参数,其他参数如下:
参数名称 | 类型 | 必须 | 最大长度 | 描述 |
---|---|---|---|---|
token | String | 是 | 256 | 反作弊结果查询token,由业务前端页面提交给业务后端。 |
account | String | 是 | 256 | 用户唯一标识,如果是手机号or邮箱,支持传入hash值,hash算法:md5(account) |
String | 否 | 64 | 用户的邮箱,如果需要加密,支持传入hash值,hash算法:md5(email) | |
phone | String | 是 | 64 | 默认国内手机号。如有海外手机,需包含国家地区代码,格式为”地区代码-手机号码“。如果需要加密,支持传入hash值,使用MD5算法对1开头,11位纯数字手机号进行加密后的值,32位小写,hash算法:md5(phone) |
ip | String | 是 | 20 | 用户参加活动时的ip |
registerTime | Number | 否 | 13 | 用户的注册时间,单位:秒 |
registerIp | String | 否 | 20 | 用户的注册IP |
activityId | String | 否 | 256 | 活动的唯一标识 |
target | String | 否 | 256 | 活动操作的目标,比如:A给B点赞,则target为B。如果target是手机号或邮箱,请提供hash值,hash算法:md5(target) |
extData | String | 否 | 2048 | 额外信息,建议自己构造json结构 |
响应结果
- 参数说明
响应字段如下,通用响应字段已省略,详细参见:通用响应结果。
参数名 | 类型 | 描述 |
---|---|---|
action | int | 检测结果:0 正常(放行),10 正常(观察),20 致命(拦截) |
hitType | int | 命中类型,详见下方“hitType返回码及含义”表 |
taskId | String | 任务id,与检测请求一一对应,建议保存此值方便以后数据查询 |
hitMsg | String | 命中详情,开通正式定制版后支持返回,可定制返回值 |
- hitType返回码及含义
hitType值 | 含义描述 |
---|---|
0 | 正常 |
1 | 数据异常,主要表现有数据完整性校验不通过或数据伪造等 |
2 | 行为异常,主要表现有用户的操作行为(鼠标点击/移动等)无法通过行为验证模型等 |
3 | 设备模型,主要表现有设备指纹等信息无法通过设备验证模型等 |
4 | 业务模型,主要表现有撞库、批量操作、违反业务规则等 |
5 | 校验异常,主要表现有数据强校验结果异常或数据伪造等 |
6 | 模拟器,主要表现有安卓端使用手机模拟器的行为 |
7 | 越狱或ROOT,主要表现有iOS系统已越狱或Android系统已root |
8 | 浏览器异常,主要表现有浏览器分辨率等参数异常或遭篡改等 |
9 | IP异常,主要表现有终端IP画像结果为风险IP或高危IP等 |
10 | 黑名单,易盾自有及客户自定义黑名单数据 |
11 | 白名单,易盾自有及客户自定义白名单数据 |
12 | 高危账号,主要表现有团伙账号或异常共享账号等风险账号类型 |
13 | 多开小号,主要表现有批量多开 |
14 | 篡改硬件信息,主要表现为篡改硬件设备参数信息 |
15 | 篡改系统信息,主要表现为篡改系统参数信息 |
16 | 高危设备,主要表现为高危设备画像风险评分,黑产特征设备等类型 |
17 | 群控或云控,主要表现为群控工作室设备或云机 |
18 | 安装修改工具,主要表现有安装Hook修改、Xposed修改,Magisk修改等 |
19 | 虚拟环境,非真实设备访问环境,区别于安卓模拟器,如编辑后台等 |
20 | 脚本工具,黑灰产用于作弊行为的脚本工具 |
- 响应结果示例
反作弊识别为正常的响应结果:
{
"code":200,
"msg":"ok",
"result":{
"action":0,
"hitType":0,
"taskId":"12345678900987654321123456789000"
}
}
反作弊识别为作弊的响应结果:
{
"code":200,
"msg":"ok",
"result":{
"action":20,
"hitType":4,
"hitMsg":"正式定制版在这个字段会返回命中详情",
"taskId":"12345678900987654321123456789000"
}
}
示例代码
public class ActivityProtectionChecker {
/** 产品密钥ID,产品标识 */
private static final String SECRET_ID = "your secret id";
/** 产品私有密钥,服务端生成签名信息使用,请严格保管,避免泄露 */
private static final String SECRET_KEY = "your secret key";
/** 业务ID,易盾根据产品业务特点分配 */
private static final String BUSINESS_ID = "your business id";
/** 易盾营销反作弊检测接口地址 */
private static final String API_URL = "https://ac.dun.163.com/v2/activity/check";
/** 实例化HttpClient,发送http请求使用,可根据需要自行调参 */
private static final HttpClient httpClient = HttpClient4Utils.createHttpClient(100, 20, 1000, 1000, 1000);
public static void main(String[] args) throws Exception {
String token = "9ca17ae2e6ffcda170e2e6ee95c13ba8888aa6ee4df2b3fe8af241f59d9e8dc15eb3bcafd9b84ba1ebacbaef2af0feaec3b92a87abafb2f64e82bfb995e65387ae00d0bc50ac9b9a91cd5cb8bda697fb72839bee9e";
String account = "100002";
String email = "zhangsanzuiniu@163.com";
String phone = "18888888888";
String loginIp = "123.123.123.120";
String registerTime = "1479178545";
String registerIp = "123.123.123.123";
String activityId = "168168";
String target = "100003";
Map<String, String> params = new HashMap<String, String>();
params.put("version", "200");
params.put("secretId", SECRET_ID);
params.put("businessId", BUSINESS_ID);
params.put("timestamp", System.currentTimeMillis() / 1000 + "");
params.put("nonce", Math.random() + "");
params.put("token", token);
params.put("account", account);
// 对邮箱取md5
params.put("email", md5(email));
// 对手机号取md5
params.put("phone", md5(phone));
params.put("ip", loginIp);
params.put("registerTime", registerTime);
params.put("registerIp", registerIp);
params.put("activityId", activityId);
params.put("target", target);
// 生成签名,参见签名过程的示例代码
params.put("signature", SignatureUtils.genSignature(SECRET_KEY, params));
// 发送check请求,业务方可以选择自己熟悉的工具包发送请求
// 请特别注意,调用接口时,请设置http超时时间
// 建议http超时的情况下,认为识别结果为“正常”
String response = HttpClient4Utils.sendPost(httpClient, API_URL, params, Consts.UTF_8);
try {
// 解析响应
JsonObject jObject = new JsonParser()
.parse(response).getAsJsonObject();
int code = jObject.get("code").getAsInt();
String msg = jObject.get("msg").getAsString();
if (code == 200) {
JsonObject dataObject = jObject.getAsJsonObject("result");
int action = dataObject.get("action").getAsInt();
if (action == 0) {
System.out.println("正常(放行)");
} else if (action == 10) {
System.out.println("正常(观察)");
} else if (action == 20) {
System.out.println("致命(拦截)");
}
} else {
System.out.println(String.format("ERROR: code=%d, msg=%s", code, msg));
}
} catch (Exception e) {
System.out.println("接口调用异常(超时 等),当作[正常]处理");
e.printStackTrace();
}
}
}
- 备注:示例代码中的HttpClient4Utils、SignatureUtils工具类参见点击查看详情