[Huawei Developers] Sherlock F:
Introduction

Safety Detect builds robust security capabilities, including system integrity check (SysIntegrity), app security check (AppsCheck), malicious URL check (URLCheck), fake user detection (UserDetect), and malicious Wi-Fi detection (WifiDetect), into your app, effectively protecting it against security threats.

SysIntegrity API: Checks whether the device running your app is secure, for example, whether it is rooted.

AppsCheck API: Checks for malicious apps and provides you with a list of malicious apps.

URLCheck API: Determines the threat type of a specific URL.

UserDetect API: Checks whether your app is interacting with a fake user.

WifiDetect API: Checks whether the Wi-Fi to be connected is secure.

Regions and Languages

For details, please refer to supported regions and languages.

UserDetect is only available outside of the Chinese mainland.

WiFi Detect is only available inside of the Chinese mainland.

Implementation

Before you get started, you must register as a HUAWEI developer and complete identity verification on the HUAWEI Developer website. For details, please refer to Register a HUAWEI ID.

Integration HMS Core Sdk

After that, follow the steps in the link below to integrate HMS Core Sdk into the project and for more details about creating a new project on AppGallery Connect . Follow the link below.

https://medium.com/huawei-developers/android-integrating-your-apps-with-huawei-hms-core-1f1e2a090e98

Enable Safety Detect

Enable the Safety Detect in the Manage API section and add the Safety Detect sdk to build.gradle in the app directory from Android Studio.

implementation 'com.huawei.hms:safetydetect:5.0.2.300'

Finally, On the Project Setting page, click agconnect-services.json to download the configuration file and copy the agconnect-services.json file to the app root directory. We have completed the necessary preparations to use the safety detect. Let’s see how to use the functions.

Importing SysIntegrity API

The SysIntegrity API is called to check the system integrity of a device. If the device is not safe, appropriate measures are taken. The API evaluates the system integrity in the secure boot process in the Trusted Execution Environment (TEE) and will dynamically evaluate the system integrity. The check results are high reliable. For example, whether the phone has root access can be checked with this API.

public void invoke() {
byte[] nonce = new byte[24];
try {
SecureRandom random;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
random = SecureRandom.getInstanceStrong();
} else {
random = SecureRandom.getInstance("SHA1PRNG");
}
random.nextBytes(nonce);
} catch (
NoSuchAlgorithmException e) {
Log.e(TAG, e.getMessage());
}
// TODO(developer): Change your app ID. You can obtain your app ID in AppGallery Connect.
Task task = client.sysIntegrity(nonce, APP_ID);
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();
String[] jwsSplit = jwsStr.split("\\.");
String jwsPayloadStr = jwsSplit[1];
String payloadDetail = new String(Base64.decode(jwsPayloadStr.getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE), StandardCharsets.UTF_8);
try {
final JSONObject jsonObject = new JSONObject(payloadDetail);
final boolean basicIntegrity = jsonObject.getBoolean("basicIntegrity");
String isBasicIntegrity = String.valueOf(basicIntegrity);
String basicIntegrityResult = "Basic Integrity: " + isBasicIntegrity;
Log.i(TAG, basicIntegrityResult);
if (!basicIntegrity) {
String advice = "Advice: " + jsonObject.getString("advice");
Log.i("Advice log", advice);
}
} catch (JSONException e) {
String errorMsg = e.getMessage();
Log.e(TAG, errorMsg != null ? errorMsg : "unknown error");
}
}
}).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());
}
}
});
}

When calling the SysIntegrity API of Safety Detect, you must transfer a nonce value that will be contained in the check result. You can check the nonce value to determine whether the returned result corresponds to your request and does not encounter replay attacks.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200907135127.49024406655701050791311528527563:50510924024418:2800:036B47D7A28367448D7A2B4CEA9A656EF088365C38E86F17C82BD12615F866AC.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200907135127.49024406655701050791311528527563:50510924024418:2800:036B47D7A28367448D7A2B4CEA9A656EF088365C38E86F17C82BD12615F866AC.png[/IMG]

The SysIntegrity API has two input parameters. The first one is the nonce value, and the other is appId. Huawei Mobile Services (APK) sends the check result to the Huawei server to verify the certificate and sends the result to you via the SysIntegrityResp object. With the getResult () method, we can get the response in JSON Web Signature (JWS) format. After doing the parse operations, we get the value of basicIntegrity.

If the value of basicIntegrity is false in the check result, you can decide whether to remind users of the risks based on your security requirements.

Importing AppsCheck

You can obtain a list of malicious applications and evaluate whether you can restrict the behavior of your application based on the risk. AppsCheck API provide developer apps with a list of malicious apps on HUAWEI mobile phones.

public void invokeGetMaliciousApps() {
Task task = client.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());
}
}
});
}

You can directly call getMaliciousAppsList() of the SafetyDetectClient to obtain a list of malicious apps. If you have no malicious apps, the log “There are no known potentially malicious apps installed” is shown .

Importing User Detect

This API can help your app prevent batch registration, credential stuffing attacks, activity bonus hunting, and content crawling.If a user is a suspicious one or risky one, a verification code is sent to the user for secondary verification.

Working principles :

(1) Your app integrates the HMS SDK to call HMS Core Safety Detect.

(2) Safety Detect evaluates risks in the device environment. If the risk level is medium or high, Safety Detect requires captcha and returns a response token to your app.

(3) Your app sends the response token to the app server.

(4) The app server sends the response token to the Safety Detect server to request the detection results.

To initiate a detection request, you need to call the userDetection method. Generally, this method is triggered when a user touches a UI control (such as a button). To call the userDetection() method, perform the following steps:

public void detect() {
Log.i(TAG, "User detection start.");
SafetyDetect.getClient(context)
.userDetection(APP_ID)
.addOnSuccessListener(new OnSuccessListener<UserDetectResponse>() {
@Override
public void onSuccess(UserDetectResponse userDetectResponse) {
Log.i(TAG, "User detection succeed, response = " + userDetectResponse);
boolean verifySucceed = verify(userDetectResponse.getResponseToken());
if (verifySucceed) {
Toast.makeText(context.getApplicationContext(),
"User detection succeed and verify succeed",
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(context.getApplicationContext(),
"User detection succeed but verify fail,"
+ "please replace verify url with your's server address",
Toast.LENGTH_SHORT)
.show();
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
String errorMsg;
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
errorMsg = SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode())
+ ": " + apiException.getMessage();
} else {
errorMsg = e.getMessage();
}
Log.i(TAG, "User detection fail. Error info: " + errorMsg);
Toast.makeText(context.getApplicationContext(), errorMsg, Toast.LENGTH_SHORT).show();
}
});
}

If the OnSuccess () method is run in the UserDetect API, the user has completed human-machine authentication. However, you still need to validate the user’s response token on the background server. To obtaining the Detection Result , You need to get an access token and call the cloud-side API to obtain the detection result. You can see the details below.

private static boolean verify(final String responseToken) {
try {
return new AsyncTask<String, Void, Boolean>() {
@Override
protected Boolean doInBackground(String... strings) {
String input = strings[0];
JSONObject jsonObject = new JSONObject();
try {
// TODO(developer): Replace the baseUrl with your own server address,better not hard code.
String baseUrl = "https://www.example.com/userdetect/verify";
jsonObject.put("response", input);
String result = sendPost(baseUrl, jsonObject);
JSONObject resultJson = new JSONObject(result);
boolean success = resultJson.getBoolean("success");
// if success is true that means the user is real human instead of a robot.
Log.i(TAG, "verify: result = " + success);
return success;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}.execute(responseToken).get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
return false;
}
}

Importing Wifi detect

Your app can detect ARP attacks, man-in-the-middle attacks, DNS hijacking attacks, and other attacks on the Wi-Fi to be connected with Wifi Detect Api. If attacks are detected, your app can interrupt the user operation or ask users to confirm whether to continue the operation.

public void invokeGetWifiDetectStatus() {
Log.i(TAG, "Start to getWifiDetectStatus!");
Task task = client.getWifiDetectStatus();
task.addOnSuccessListener(new OnSuccessListener<WifiDetectResponse>() {
@Override
public void onSuccess(WifiDetectResponse wifiDetectResponse) {
int wifiDetectStatus = wifiDetectResponse.getWifiDetectStatus();
Log.i(TAG, "\n-1: Failed to obtain the Wi-Fi status. \n" + "0: No Wi-Fi is connected. \n" + "1: The connected Wi-Fi is secure. \n" + "2: The connected Wi-Fi is insecure.");
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());
}
}
});
}

Wifi Detect Status:

1: Failed to obtain the Wi-Fi status.

0: No Wi-Fi is connected.

1: The connected Wi-Fi is secure.

2: The connected Wi-Fi is insecure.

Importing Url Check

When you visit a URL ,this API checks whether the URL is a malicious one. If so, you can evaluate the risk and alert the user about the risk or block the URL.

Main steps:

Initialize the URLCheck API.

Request URL check.

Close the URL check session.

Process the result code.

public void callUrlCheckApi() {
client.urlCheck("https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/SafetyDetectWiFiDetectAPIDevelopment", APP_ID,
// Specify url threat type
UrlCheckThreat.MALWARE,
UrlCheckThreat.PHISHING)
.addOnSuccessListener(new OnSuccessListener<UrlCheckResponse>() {
/**
* Called after successfully communicating with the SafetyDetect API.
* The #onSuccess callback receives an
* {@link com.huawei.hms.support.api.entity.safetydetect.UrlCheckResponse} that contains a
* list of UrlCheckThreat that contains the threat type of the Url.
*/
@Override
public void onSuccess(UrlCheckResponse urlCheckResponse) {
// Indicates communication with the service was successful.
// Identify any detected threats.
// Call getUrlCheckResponse method of UrlCheckResponse then you can get List<UrlCheckThreat> .
// If List<UrlCheckThreat> is empty , that means no threats found , else that means threats found.
List<UrlCheckThreat> list = urlCheckResponse.getUrlCheckResponse();
if (list.isEmpty()) {
// No threats found.
Log.i(TAG,"No Threats found!");
} else {
// Threats found!
Log.i(TAG,"Threats found!");
}
}
})
.addOnFailureListener(new OnFailureListener() {
/**
* Called when an error occurred when communicating with the SafetyDetect API.
*/
@Override
public void onFailure(Exception e) {
// An error with the Huawei Mobile Service API contains some additional details.
String errorMsg;
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
errorMsg = "Error: " +
SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " +
e.getMessage();
// You can use the apiException.getStatusCode() method to get the status code.
// Note: If the status code is SafetyDetectStatusCodes.CHECK_WITHOUT_INIT, you need to call initUrlCheck().
} else {
// Unknown type of error has occurred.
errorMsg = e.getMessage();
}
Log.d(TAG, errorMsg);
Toast.makeText(context.getApplicationContext(), errorMsg, Toast.LENGTH_SHORT).show();
}
});
}

You need to call the getUrlCheckResponse() method of the URLCheckResponse object to obtain the URL check response. The method returns List<UrlCheckThreat> which contains a list of all detected URL threat types. If the list is empty, no threat has been detected. Otherwise, you can call the getUrlCheckResult () method of UrlCheckThreat to obtain the specific threat code. For more detail follow this link.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200915140307.36028659160948836149060907179278:50510924024418:2800:B8575C0894DADF2620BF162CE5C70D97FAAE5E0F0BDC8A8D057D36CEA06639ED.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200915140307.36028659160948836149060907179278:50510924024418:2800:B8575C0894DADF2620BF162CE5C70D97FAAE5E0F0BDC8A8D057D36CEA06639ED.png[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200915141124.54075366846050000065938036363998:50510924024418:2800:3390F516B22D81007BD7151E5B3DD51FB627B8D1065D410E11AAD2E59CDC1793.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/026/360/265/5190090000026360265.20200915141124.54075366846050000065938036363998:50510924024418:2800:3390F516B22D81007BD7151E5B3DD51FB627B8D1065D410E11AAD2E59CDC1793.png[/IMG]

Resources:

Github link : https://github.com/simgekeser/Hms-Safety-Detect-Example

Official Document : https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/SafetyDetect_AbouttheService