简介

Safety Detect提供系统完整性检测(SysIntegrity)、应用安全检测(AppsCheck)、恶意URL检测(URLCheck)、虚假用户检测(UserDetect)、恶意Wi-Fi检测(WifiDetect),可帮助保护应用程序免受安全威胁。

SysIntegrity API:系统完整性检测API,开发者可通过该API评估其App所运行的设备环境是否安全(如设备是否被root)。

AppsCheck API:应用安全检测API,开发者可通过该API获取恶意应用列表。

URLCheck API:恶意URL检测API,开发者可通过该API来确定特定URL的威胁类型。

UserDetect API:虚假用户检测API,开发者可通过该API判断当前App的交互对象是否为虚假用户。

WifiDetect API:恶意Wi-Fi检测API,开发者可通过该API检测当前尝试连接的Wi-Fi是否安全。

您将建立什么

在这个Codelab中,您将使用已经创建好的Demo Project实现对华为系统完整性检测应用安全检测、恶意URL检测、虚假用户检测、恶意Wi-Fi检测的API调用,通过Demo Project你可以体验到:

系统完整性检测:

应用安全检测:

恶意URL检测:

虚假用户检测:

恶意Wi-Fi检测:

您将会学到什么

硬件要求

软件要求

集成HUAWEI HMS Core能力,需要完成以下准备工作:

具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。

打开服务开关

  1. 华为开发者联盟管理中心页面,点击"我的应用 > 应用名 > 开发 > API 管理"。
  2. 打开"Safety Detect"服务开关。

添加当前应用的AGC配置文件

  1. 华为开发者联盟管理中心页面,点击"我的应用 > 应用名 > 开发",下载配置文件 "agconnect-services.json"
  2. 将下载的"agconnect-services.json"文件移至Android Studio开发工程app的根目录下。

添加SDK依赖

1.打开应用级的build.gradle文件。

2.在"dependencies"中添加编译依赖。

dependencies { // Add the following line implementation 'com.huawei.hms:safetydetect:5.0.1.300' }

配置混淆脚本

1.开发者编译APK前需要配置不要混淆HMS Core SDK,避免功能异常。

打开工程的混淆配置文件。

加入排除HMS Core SDK的混淆配置。

-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile, LineNumberTable -keep class com.hianalytics.android.** {*; } -keep class com.huawei.updatesdk.** {*; } -keep class com.huawei.hms.** {*; }

2.如果开发者使用了AndResGuard,需要在混淆配置文件中加入AndResGuard允许清单。

"R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*"

3.点击Sync Now同步工程。

系统完整性检测

调用SysIntefrity API主要分为四个步骤:

  1. 获取nonce。
  2. 请求 Safety Detect SysIntegrity。
  3. 在您的服务器中验证检测结果(签名,证书链,域名)。

获取nonce

在调用Safety Detect SysIntegrity API时,您必须传入一个nonce值。在检测结果中会包含这个nonce值,您可以通过校验这个nonce来确定返回结果能够对应您的请求,并且没有被重放攻击。

一个nonce值只能被使用一次,nonce 值必须至少为 24 字节。推荐的做法是从发送到您的服务器的数据中派生 nonce 值。比如,使用用户名加当前时间戳作为nonce 值。

请求Safety Detect SysIntegrity

Safety Detect SysIntegrity接口有两个参数,第一个是上一小节我们获取的nonce值,第二个是appId。在开发准备中,您已经创建了一个应用,在配置签名证书指纹步骤中,您已经可以在开发者联盟的网页上获取appId了,将appId作为第二个参数传入接口:

private void invokeSysIntegrity() { SafetyDetectClient mClient = SafetyDetect.getClient(Mainactivity.this); // TODO(developer): Change the nonce generation to include your own, used once value, // ideally from your remote server. byte[] nonce = ("Sample" + System.currentTimeMillis()).getBytes(); Task task = mClient.sysIntegrity(nonce,"3*******"); task.addOnSuccessListener(new OnSuccessListener<SysIntegrityResp>() { @Override public void onSuccess(SysIntegrityResp response) { // Indicates communication with the service was successful. // Use response.getResult() to get the result data. String jwsStr = response.getResult(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // An error occurred while communicating with the service. if (e instanceof ApiException) { // An error with the HMS API contains some // additional details. ApiException apiException = (ApiException) e; // You can retrieve the status code using // the apiException.getStatusCode() method. Log.e(TAG, "Error: " + SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " + apiException.getMessage()); } else { // A different, unknown type of error occurred. Log.e(TAG, "ERROR:" + e.getMessage()); } } }); }

Safety-detect-App-sample

服务端

建议对JwsResult的处理流程如下,其中校验证书和签名的部分,需要放在您App的服务器端进行。

具体校验逻辑请获取示例代码,请下载

safety-detect-server-sample

测试

安装测试APK,点击接口调用

应用安全检测

示例代码为您演示如何完成应用安全检测API调用并获取检测结果。

客户端

您可直接调用Apps Check getMaliciousApps获取恶意应用列表

private void invokeGetMaliciousApps() { SafetyDetectClient appsCheckClient = SafetyDetect.getClient(MainActivity.this); Task task = appsCheckClient.getMaliciousAppsList(); task.addOnSuccessListener(new OnSuccessListener<MaliciousAppsListResp>() { @Override public void onSuccess(MaliciousAppsListResp maliciousAppsListResp) { // Indicates communication with the service was successful. // Use resp.getMaliciousApps() to get malicious apps data. List<MaliciousAppsData> appsDataList = maliciousAppsListResp.getMaliciousAppsList(); // Indicates get malicious apps was successful. if (maliciousAppsListResp.getRtnCode() == CommonCode.OK) { if (appsDataList.isEmpty()) { // Indicates there are no known malicious apps. Log.i(TAG, "There are no known potentially malicious apps installed."); } else { Log.i(TAG, "Potentially malicious apps are installed!"); for (MaliciousAppsData maliciousApp : appsDataList) { Log.i(TAG, "Information about a malicious app:"); // Use getApkPackageName() to get APK name of malicious app. Log.i(TAG, "APK: " + maliciousApp.getApkPackageName()); // Use getApkSha256() to get APK sha256 of malicious app. Log.i(TAG, "SHA-256: " + maliciousApp.getApkSha256()); // Use getApkCategory() to get category of malicious app. // Categories are defined in AppsCheckConstants Log.i(TAG, "Category: " + maliciousApp.getApkCategory()); } } } else { Log.e(TAG, "getMaliciousAppsList fialed: " + maliciousAppsListResp.getErrorReason()); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // An error occurred while communicating with the service. if (e instanceof ApiException) { // An error with the HMS API contains some // additional details. ApiException apiException = (ApiException) e; // You can retrieve the status code using the apiException.getStatusCode() method. Log.e(TAG, "Error: " + SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " + apiException.getStatusMessage()); } else { // A different, unknown type of error occurred. Log.e(TAG, "ERROR: " + e.getMessage()); } } }); }

测试

点击"GET HARMFUL APPS LIST":

恶意URL检测

调用URLCheck API主要分为四个步骤:

  1. 初始化URLCheck API。
  2. 请求网址检测。
  3. 关闭网址检测会话。
  4. 处理错误码。

初始化URLCheck API

在使用URLCheck API前,必须调用initUrlChecker()方法进行接口初始化,并且需要等待初始化完成后再进行接下来的接口调用,示例代码如下:

SafetyDetectClient client = SafetyDetect.getClient(getActivity()); client.initUrlCheck();

请求网址检测

指定关注的威胁类型,您可以将关注的威胁类型作为网址检测API的参数。 其中,UrlCheckerThreat类中的常量包含了当前支持的威胁类型:

package com.huawei.hms.safetydetect; public class UrlCheckerThreat { /** * 此类型URL被标记为包含潜在有害应用的页面的URL(篡改首页、网页挂马、恶意应用下载链接等) */ public static final int MALWARE = 1; /** * 这种类型的URL被标记为钓鱼、欺诈网站 */ public static final int PHISHING = 3; }

发起网址检测请求,待检测的URL包含协议、主机、路径,不包含查询参数。调用API示例代码如下:

String url = "https://developer.huawei.com/consumer/cn/"; SafetyDetect.getClient(this).urlCheck(url, appId, UrlCheckerThreat.MALWARE, UrlCheckerThreat.PHISHING) .addOnSuccessListener(this, new OnSuccessListener<SafetyDetectApi.URLCheckerResponse>() { @Override public void onSuccess(SafetyDetectApi.URLCheckerResponse urlResponse) { // 表示与服务通信已成功,识别检测到的威胁. if (urlResponse.getDetectedThreats().isEmpty()) { // 无威胁 } else { // 存在威胁! } } }) .addOnFailureListener(this, new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // 与服务通信发生错误. if (e instanceof ApiException) { // HMS发生错误的状态码及对应的错误详情. ApiException apiException = (ApiException) e; Log.d(TAG, "Error: " + CommonStatusCodes .getStatusCodeString(apiException.getStatusCode())); // 注意:如果状态码是SafetyDetectStatusCode.ERROR_URL_CHECKER_API_NOT_INITIALIZED, // 这意味着您未调用initUrlChecker()或者调用未完成就发起了网址检测请求, // 或者在初始化过程中发生了内部错误需要重新进行初始化,需要重新调用initUrlChecker() } else { // 发生未知类型的异常. Log.d(TAG, "Error: " + e.getMessage()); } } });

获取网址检测的响应,调用返回对象URLCheckerResponse的getUrlCheckerResponse ()方法,返回List<UrlCheckerThreat>, 包含检测到的URL威胁类型。若该列表为空,则表示未检测到威胁,否则,可调用UrlCheckerThreat中的getUrlCheckResult ()取得具体的威胁代码。示例代码如下:

final EditText testRes = getActivity().findViewById(R.id.fg_call_urlResult); List<UrlCheckerThreat> list = urlCheckerResponse.getUrlCheckerResponse(); if (list.isEmpty()) { testRes.setText("ok"); } else { for (UrlCheckerThreat threat : list) { int type = threat.getUrlCheckResult(); } }

关闭网址检测会话

如果您的应用不再使用或长时间不再调用网址检测接口,请调用shutdownUrlChecker()方法关闭网址检测会话,释放资源:

SafetyDetect.getClient(this).shutdownUrlChecker();

测试

安装测试APK,以此点击接口调用

虚假用户检测

示例代码分为两个部分:客户端部分展示API调用并获取检测结果;服务端部分展示如何获取虚假用户检测最终结果。

调用UserDetect API

调用UserDetect API分为两步:

  1. 发起检测请求:调用UserDetect API的userDetection()方法以发起虚假用户检测请求,API会返回一个response token。
  2. 获取检测结果:使用步骤1获取response token调用云端verify获取检测结果:

初始化Bot行为检测

UserDetect提供了行为检测能力,如果您希望您的虚假用户检测功能具备该能力,可以通过调用initUserDetect()接口初始化虚假用户检测,示例代码如下:

// Replace with your activity or context as a parameter. SafetyDetectClient client = SafetyDetect.getClient(MainActivity.this); client.initUserDetect().addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void v) { // Indicates communication with the service was successful. } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // There was an error communicating with the service. } });

发起检测请求

您需要通过调用userDetection发起检测。通常在用户点击UI组件(如一个按钮)后触发调用该方法。调用userDetection方法时,您需要做以下事情:

  1. 传入您申请的appId作为该方法的参数。
  2. 分别添加OnSuccessListener和OnFailureListener实例作为监听器。
  3. 重写onSuccess、onFailure,处理对应的结果。

调用该方法的示例代码如下所示:

final Task<UserDetectResponse> task = client.userDetection(APP_ID); task.addOnSuccessListener(new OnSuccessListener() { //success to get result from userDetection API @Override public void onSuccess(Object obj) { UserDetectResponse userDetectResponse = (UserDetectResponse) obj; String responseToken = userDetectResponse.getResponseToken(); //Send the response token to your own app server,so that you can get the final result //of user detect service. Replace the verify method with your own code here. String result = verify(responseToken); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { } });

获取检测结果

服务端主要分为两步:

  1. 获取accessToken。
  2. 调用云侧API获取检测结果。

具体步骤如下:

获取accessToken
详细请参见开放平台鉴权相关内容描述
调用云侧API获取检测结果:调用云侧获取结果。消息请求示例如下所示。

POST https://rms-api.cloud.huawei.com/rms/v1/userRisks/verify?appId=123456 HTTP/1.1 Content-Type: application/json;charset=utf-8 {"accessToken":"AAWWHI94sgUR2RU5_P1ZptUiwLq7W8XWJO2LxaAPuXw4_HOJFXnBlN-q5_3bwlxVW_SHeDPx_s5bWW-9DjtWZsvcm9CwXe1FHJg0u-D2pcQPcb3sTxDTJeiwEb9WBPl_9w","response":"bc9d6e73-b422-4d7c-8464-2a8b5ad5b525" }

更多关于请求接口的详细信息可以参照API参考

App端关闭虚假用户检测:

您可以通过调用shutdownUserDetect()接口关闭虚假用户检测功能,释放资源,示例代码如下:

// Replace with your activity or context as a parameter. SafetyDetectClient client = SafetyDetect.getClient(MainActivity.this); client.shutdownUserDetect().addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void v) { // Indicates communication with the service was successful. } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // There was an error communicating with the service. } });

测试

安装测试APK,以此点击接口调用

恶意Wi-Fi检测

示例代码为您演示如何完成恶意Wi-Fi检测API调用并获取检测结果。

客户端

您可直接调用SafetyDetectClient的getWifiDetectStatus()获取恶意Wi-Fi检测结果。

private void invokeGetWifiDetectStatus() { Log.i(TAG, "Start to getWifiDetectStatus!"); SafetyDetectClient wifidetectClient = SafetyDetect.getClient(getApplicationContext()); Task task = wifidetectClient.getWifiDetectStatus(); task.addOnSuccessListener(new OnSuccessListener<WifiDetectResponse>() { @Override public void onSuccess(WifiDetectResponse wifiDetectResponse) { int wifiDetectStatus = wifiDetectResponse.getWifiDetectStatus(); Log.i(TAG, "\n-1 :获取WiFi状态失败\n" + "0 :未连接WIFI\n" + "1 :当前连接的WIFI安全\n" + "2 :当前连接的WIFI不安全."); Log.i(TAG, "wifiDetectStatus is: " + wifiDetectStatus); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException apiException = (ApiException) e; Log.e(TAG, "Error: " + apiException.getStatusCode() + ":" + SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " + apiException.getStatusMessage()); } else { Log.e(TAG, "ERROR! " + e.getMessage()); } } }); }

测试

点击"GET WIFIDETECT STATUS":

干得好,您已经成功完成了Codelab并学到了:

您可以阅读下面链接,了解更多相关的信息。

相关文档

您可以点击下方按钮下载源码。

源码下载

已复制代码