KiwiGuard SDK(iOS)下载与接入文档
1 名称解释
序号 | 名词 | 描述 |
1 | 应用组 | 相同App(不同版本、不同渠道)的集合,便于更好的管理企业内的应用矩阵,首次使用时需创建应用组 |
3 | appGroupID | 应用组ID:POST请求参数,能够发送POST请求访问几维安全服务端接口,获取应用组下所有App的终端威胁信息,需搭配appGroupSecret使用 |
4 | appGroupSecret | 密钥:POST请求参数,能够发送POST请求访问几维安全服务端接口,获取应用的终端威胁信息,需搭配appGroupID或appID使用 |
5 | appID | AppID:POST请求参数,能够发送POST请求访问几维安全服务端接口,获取当前App名称、版本及渠道下的终端威胁信息,需搭配appGroupSecret使用 |
2 法规要求
您应向您的终端用户逐一明示您嵌入的第三方SDK收集使用个人信息的目的、方式和范围。
您应当在《隐私政策》中明确告知终端用户,您选择了成都盈海益讯科技有限公司作为合作方,并委托其收集、使用、加工和处理终端用户个人信息。成都盈海益讯科技有限公司建议您在《隐私政策》中的“我们如何共享、转让、公开披露您的个人信息”的表述条款中增加如下内容(关于个人信息共享给第三方说明的部分,强烈建议此部分由您专业的法务团队优化完善,详情可参考《KiwiGuard SDK隐私政策》):
为了识别客户端或终端用户的异常状态,为了对盗版应用、虚假设备、游戏外挂、环境风险、对抗事件等威胁场景进行监测与管控,我们的产品会集成第三方的SDK或类似应用程序,具体如下:
SDK名称 | KiwiGuard SDK |
所属公司名称 | 成都盈海益讯科技有限公司 |
SDK收集数据类型 | |
SDK用途 | (1)计算设备唯一标识码(设备指纹)(2)识别终端威胁异常信息;(3)对威胁异常进行管控。 |
3 KiwiGuard SDK手动接入流程
3.1 KiwiGuard SDK前端接入
集成KiwiGuard SDK之前:请先在几维安全《移动应用安全管理平台》创建应用组、创建App,获取appID。
3.1.1 集成KiwiGuard SDK
3.1.2 接口使用说明
3.2 KiwiGuard SDK后端接入
备注:本节可通过访问几维安全服务端API获取终端威胁数据源;可在App测试环节与上线后进行操作。
3.2.1 HTTP接口接入方法
(1) 接口地址
接口地址 | |
请求方式 | POST |
Content-Type | application/json |
(2) 请求参数
字段 | 类型 | 传入说明 | 描述 |
deviceToken | string | 必传参数 | 用户前端获取的deviceToken |
timestamp | string | 必传参数 | 调用服务的秒级时间戳 (例如:“1650934578”),用来计算sign |
sign | string | 必传参数 | 查询数据时服务端校验数据是否篡改的字段(通过appGroupSecret,deviceToken,timestamp指定规则字符串后通过md5字符串加密生成的32位加密后的字符串,见下方代码示例) |
appGroupID | string | 请求参数中两者必须选填一个 | 几维安全SaaS平台获取(用来获取应用组下所有接入SDK的应用终端威胁信息) |
appID | string | 前往几维安全Saas平台获取(用来获取当前应用的终端威胁信息) |
*如何生成参数sign?
【Python实例】
① 构建待加密的指定规则字符串 ;
AppGroupSecret: 几维安全SaaS平台获取( KiwiGuard > 应用管理 > 应用组AppGroupSecret )
encrypt_key = 'secret:{AppGroupSecret}*{deviceToken}*{timestamp}:encrypt'.format(AppGroupSecret=AppGroupSecret, deviceToken=deviceToken, timestamp=timestamp)
② 使用md5加密,获取加密后的数据传递给sign字段;
import hashlib
m = hashlib.md5()
m.update(encrypt_key.encode())
sign = m.hexdigest()
【Java实例】
// 封装的计算sign函数
public String getStrArrMd5Sign(String []strArr){
StringBuilder sb = new StringBuilder();
String signStr = null, signMd5 = null;
if(strArr != null && strArr.length > 0){
sb.append("secret:");
for(int i=0; i<strArr.length; i++){
sb.append(strArr[i]);
if(i != (strArr.length-1))
sb.append("*");
}
sb.append(":encrypt");
signStr = sb.toString();
Log.d(TAG,signStr);
if(!signStr.isEmpty()){
MessageDigest md = null;
try{
md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(signStr.getBytes());
signMd5 = new BigInteger(1, md.digest()).toString(16);
// (fix)不满32位前面添加0
while(signMd5.length() < 32 ){
signMd5 = "0" + signMd5;
}
}catch (Exception e){
Log.d(TAG,"no such MD5 algorithm"+e.getMessage());
}
}
}
return signMd5;
}
// 调用上面封装的函数获取sign
String sign = getStrArrMd5Sign(new String[]{AppGroupSecret
,deviceToken,"时间戳"});//请严格按照该拼接顺序(时间戳例如:"16509345787")
// 封装json 请求体
// appGroupID 和 appID 至少任意填一个
JSONObject jsonBody = new JSONObject();
jsonBody.put("deviceToken",deviceToken);
jsonBody.put("appGroupID","");
jsonBody.put("sign",sign);
jsonBody.put("timestamp","时间戳");
jsonBody.put("appID","");
// TODO 发起网络请求
*如何发送POST请求?
【Java实例】
public class HttpUtils {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static OkHttpClient client = new OkHttpClient();
public static Response post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url) //填写接口地址
.post(body) //填写请求参数
.build();
Response response = client.newCall(request).execute();
return response;
}
}
【Python实例】
import hashlib, requests, pprint, json
def md5_convert(string):
"""
计算字符串md5值
:param string: 输入字符串
:return: 字符串md5
"""
m = hashlib.md5()
m.update(string.encode())
return m.hexdigest()
if __name__ == '__main__':
appSecretKey = '****' # 应用管理应用组所对应的 SecretKey
deviceToken = '****' # deviceID
ts = **** # 时间戳
md5_key = 'secret:{appSecretKey}*{deviceToken}*{ts}:encrypt'.format(appSecretKey=appSecretKey, deviceToken=deviceToken, ts=ts)
sign = md5_convert(md5_key)
body = {
"appGroupID": "****", # 应用组id
,web端获取
"appID": "****", # appID,web端获取
"deviceToken": deviceToken,
"sign": sign,
"timestamp": ts
}
pprint.pprint(json.loads(requests.post(url='****', json=body).text), depth=4)
(备注:若没有查看appGroupSecret的权限,请联系几维安全工作人员。)
(3)成功响应
字段 | 类型 | 描述 |
code | int | 状态码 |
message | String | 状态描述 |
data | Json | 返回设备指纹deviceID及设备风险数据 |
uploadTime | int | 时间戳,最后一次上报异常的时间 |
成功示例:
{
"message": "success!",
"code": 1,
"data": {
"deviceID":"xxx",
"fakeRiskDevice":{
"emulator":{
key1:value1,
}
},
"environmentRiskDevice":{
"hook":{
key1:value1
key2:value2
}
},
"fightRiskDevice":{
"anti_debug":{
key1:value1
}
},
"suspiciousRiskDevice":{
"sim": {
key1:value1,
}
}
“uoloadTime”:1635486916
}
}
(4)错误响应
字段 | 类型 | 描述 |
code | int | 状态码 |
message | String | 状态描述 |
失败示例:
{
"message": '缺少查询参数!',
"code": 1880001
}
错误码 | 描述 |
1880001 | 缺少查询参数。详情看请求参数说明 |
1880002 | sign校验失败,md5生成的加密字符串错误 |
1880003 | appID 不存在,请检查 |
1880004 | appGroupID 不存在,请检查 |
1880005 | 设备指纹不存在,请检查 |
3.2.2 HTTP接口返回参数明细说明
成功响应时候,data字段Json类型的内容为:
字段 | 类型 | 描述 |
deviceID | String | 设备指纹 |
uploadTime | int | 服务端的处理时间 |
fakeRiskDevice | Json | 虚假设备相关标签信息(包含:) |
environmentRiskDevice | Json | 环境风险相关的标签信息(包含:) |
fightRiskDevice | Json | 对抗风险相关的标签信息(包含:) |
suspiousRiskDevice | Json | 可疑设备相关的标签信息(包含:) |
(1)fakeRiskDevice详细内容
① 云真机检测:
字段 | 类型 | 描述 |
cloud_machine | Json | 云真机检测 |
cloud_machine详细内容:
字段 | 类型 | 描述 |
checked | bool | 应用是否运行在云真机中 |
cloudMachineBrand | String | 云真机厂商 |
② 模拟器检测:
字段 | 类型 | 描述 |
emulator | Json | 模拟器检测 |
emulator详细内容:
字段 | 类型 | 描述 |
checked | bool | 应用是否运行在模拟器中 |
emulatorBrand | String | 模拟器类型 |
(2)environmentRiskDevice详细内容
① hook检测
字段 | 类型 | 描述 |
hook | Json | Hook行为检测 |
hook环境详细内容:
字段 | 类型 | 描述 |
checked | bool | 设备运行的终端是否为ROOT环境 |
hookTool | String | Hook框架 |
② 越狱检测
字段 | 类型 | 描述 |
jailbreak | Json | 越狱检测 |
jailbreak详细内容:
字段 | 类型 | 描述 |
checked | bool | 设备是否越狱 |
③ 签名校验检测
字段 | 类型 | 描述 |
sign | Json | 签名校验检测 |
sign详细内容:
字段 | 类型 | 描述 |
checked | bool | 设备是否越狱 |
origteamID | String | 官方TeamID |
teamID | String | 当前TeamID |
④ VPN/代理检测
字段 | 类型 | 描述 |
VPN | Json | VPN/代理检测 |
VPN详细内容:
字段 | 类型 | 描述 |
checked | bool | 是否使用VPN/代理 |
(3)fightRiskDevice详细内容
字段 | 类型 | 描述 |
anti_debug | Json | 动态调试检测 |
danti_debug详细内容:
字段 | 类型 | 描述 |
checked | bool | 是否存在动态调试行为 |
(4)suspiciousRiskDevice详细内容
① SIM卡状态检测
字段 | 类型 | 描述 |
sim | Json | SIM卡状态检测 |
sim详细内容:
字段 | 类型 | 描述 |
checked | bool | 设备SIM卡状态是否异常 |