后端接入
2022.07.11 11:06:57
规范说明
通信协议
HTTPS 协议。
请求方法
网易易盾提供的所有接口,均支持 POST/GET 方法。当参数名与参数值拼装起来的 URL 长度小于 1024 个字符时,可以用GET发起请求;当参数类型含 byte[] 类型或拼装好的请求URL过长时,必须用 POST 发起请求。建议所有API调用都使用 POST 方法请求。
当前仅支持post请求的Content-Type: application/x-www-form-urlencoded格式,不支持application/json。
字符编码
所有接口的请求和响应数据编码皆为 utf-8。
API请求结构
名称 | 描述 | 备注 |
---|---|---|
API入口 | 具体API接口地址 | 如 https://ac.dun.163.com/v3/common/check |
公共参数 | 每个接口都包含的通用参数 | 详见 公共参数 说明 |
私有参数 | 每个接口特有的参数 | 详见每个API接口定义 |
公共参数
请求公共参数
易盾营销反作弊服务的所有接口均包含这些公共参数。
参数名称 | 类型 | 必须 | 最大长度 | 描述 |
---|---|---|---|---|
version | String | 是 | 4 | 接口版本号,当前可用版本为300 |
secretId | String | 是 | 32 | 秘钥id ,由营销反作弊服务分配 |
businessId | String | 是 | 32 | 业务id,由营销反作弊服务分配 |
timestamp | Long | 是 | 13 | 请求当前 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, foobar=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接口
- 接口地址:https://ac.dun.163.com/v3/common/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 | 默认国内手机号。如有海外手机,需包含国家地区代码,格式为“+447410xxx186(+44即为国家码)”。如果需要加密,支持传入hash值,hash算法:md5(phone) |
ip | String | 是 | 20 | 用户参加活动时的ip |
registerTime | Number | 否 | 13 | 用户的注册时间,单位:毫秒 |
registerIp | String | 否 | 20 | 用户的注册IP |
nickname | String | 否 | 256 | 用户的昵称 |
userLevel | String | 否 | 32 | 用户的等级 |
activityId | String | 否 | 256 | 活动的唯一标识 |
target | String | 否 | 256 | 活动操作的目标,比如:A给B点赞,则target为B。如果target是手机号或邮箱,请提供hash值,hash算法:md5(target) |
extData | String | 否 | 2048 | 额外信息,建议自己构造json结构 |
反作弊响应结果
- 参数说明
响应字段如下,通用响应字段已省略,详细参见:通用响应结果。
参数名 | 类型 | 描述 |
---|---|---|
action | int | 检测结果:0 正常(放行),10 正常(观察),20 致命(拦截) |
taskId | String | 任务id,与检测请求一一对应,建议保存此值方便以后数据查询 |
hitInfos | List | 命中信息,例如:[{"hitType":5,"hitTypeDesc":"校验异常","hitMsg":"无SDK数据"}], 其中hitType类型为int,含义是命中类型,详见下方“hitType返回码及含义”表, hitTypeDesc类型为String,含义为命中类型的中文描述, hitMsg类型为String,含义是命中详情,内容可能为空. 如果同时命中多个类型,则会返回所有风险信息。正常情况下,action为 0(正常)时,hitInfos 中不会有信息。 |
- 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,
"taskId":"698256a52215495ab3c61f14e8e6e844",
"hitInfos":[
{
}]
}
}
反作弊识别为作弊的响应结果:
{
"code":200,
"msg":"ok",
"result":{
"action":20,
"taskId":"5aecbc658f2e4cfab24b6f4171e5839e",
"hitInfos":[
{
"hitType":5,
"hitTypeDesc":"校验异常",
"hitMsg":"正式定制版在这个字段会返回命中详情"
},
{
"hitType":6,
"hitTypeDesc":"模拟器",
"hitMsg":"正式定制版在这个字段会返回命中详情"
}
]//如果同时命中多个类型,则会返回所有风险信息
}
}
设备指纹结果
设备指纹结果默认不返回,若有需要请联系易盾策略运营开通。
响应字段如下,通用响应字段已省略,详细参见:通用响应结果。
参数名 | 类型 | 描述 |
---|---|---|
taskId | String | 任务id,与检测请求一一对应,建议保存此值方便以后数据查询 |
detail | Json | 设备信息详情,字段解释见设备指纹字段表 |
∟deviceData | Json | 设备信息详情,字段解释见设备指纹字段表 |
- iOS/Android 返回字段
参数名 | 类型 | 描述 | 终端 |
---|---|---|---|
deviceId | String | 设备唯一指纹 | iOS、Android |
osv | String | 系统版本 | iOS、Android |
model | String | 手机厂商 | iOS、Android |
appVersion | String | APP版本号 | iOS、Android |
simulator | int | 是否模拟器(0:不是模拟器,非0:是模拟器) | iOS、Android |
root | int | 是否root(0:不是root,1:是root) | iOS、Android |
flag | int | 是否被调试(0:没有被调试,非0:被调试) | iOS、Android |
isInjection | Boolean | 是否注入 | iOS、Android |
mac | String | mac地址 | Android |
- web/h5 返回字段
参数名 | 类型 | 描述 | 终端 |
---|---|---|---|
deviceId | String | 设备唯一指纹 | web/h5 |
appVersion | String | 浏览器版本信息 | web/h5 |
设备指纹识响应结果:
{
"code":200,
"msg":"ok",
"result":{
"action":0,
"taskId":"698256a52215495ab3c61f14e8e6e844",
"hitInfos":[
],
"detail": {
"deviceData": {
"appVersion": "1.0",
"osv": "6.0",
"simulator": 2,
"flag": 0,
"root": 1,
"model": "M55 Note",
"isInjection": false,
"deviceId": "41c75882d231afec0dbf2d54d18c66df",
"mac": "a4:49:d1:e4:6d:d7"
}
}
}
}
完整示例代码
public class AnticheatProtectionChecker {
/** 产品密钥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/v3/common/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";
String nickname = "yidun";
String userLevel = "level1";
Map<String, String> params = new HashMap<String, String>();
params.put("version", "300");
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("nickname", nickname);
params.put("userLevel", userLevel);
// 生成签名,参见签名过程的示例代码
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工具类参见点击查看详情