小言_互联网的博客

用免费开放的华为安全检测功能,评估App运行设备安全

664人阅读  评论(0)

前言

系统完整性检测,是App需具备的一个实用功能。我们都知道,在系统不完整的手机上,例如被root过,运行App将面临被恶意攻击、窃取隐私等威胁,尤其是商城类App,购买环节的环境安全性至关重要,因此在App中增加能快速检测手机系统风险的功能必不可少。

这一重要功能目前是免费,其基本的技术原理是,App集成华为HMS Core的SDK,调用免费提供的安全检测服务,在TEE可信执行环境中评估,得到的检测结果经过X.509数字证书签名,双重保障下,检测到的结果真实可信、不会被恶意更改~

功能运行起来的效果:

以下是开发过程,分享给大家。

开发前准备

 

1.1 Android studio安装

还没装开发工具的小伙伴下载指路:Android studio官网下载

1.2 在AppGallery Connect中配置相关信息

在开发应用前,需在AppGallery Connect中配置相关信息。具体操作步骤

1.3 配置华为maven仓地址

打开Android Studio项目级“build.gradle”文件:

 

添加HUAWEI agcp插件以及Maven代码库:

  1. 在“buildscript > repositories”中配置HMS Core SDK的Maven仓地址。
  2. 在“allprojects > repositories”中配置HMS Core SDK的Maven仓地址。
  3. 如果App中添加了“agconnect-services.json”文件则需要在“buildscript > dependencies”中增加agcp配置。

  
  1. buildscript {
  2. repositories {
  3. google()
  4. jcenter()
  5. // 配置HMS Core SDK的Maven仓地址。
  6. maven {url 'https://developer.huawei.com/repo/'}
  7. }
  8. dependencies {
  9. ...
  10. // 增加agcp配置。
  11. classpath 'com.huawei.agconnect:agcp:1.4.2.300'
  12. }
  13. }
  14. allprojects {
  15. repositories {
  16. google()
  17. jcenter()
  18. // 配置HMS Core SDK的Maven仓地址。
  19. maven {url 'https://developer.huawei.com/repo/'}
  20. }
  21. }

这里需要说明的是,Maven仓地址只能在IDE中配置。需要添加多个Maven代码库的话,将华为公司的Maven仓地址配置在最后哦。

1.4 添加编译依赖

打开应用级的“build.gradle”文件:

 在文件头apply plugin: 'com.android.application'下一行添加如下配置:

apply plugin: 'com.huawei.agconnect'

 在“dependencies”中添加如下编译依赖:


  
  1. dependencies {
  2. implementation 'com.huawei.hms:safetydetect:5.0.5.302'
  3. }

 

1.5 配置混淆脚本

如果你自己开发时要用到AndResGuard,那就还需要在应用级的“build.gradle”文件中加入AndResGuard允许清单,代码可以参考官网的混淆配置

 

代码开发

 

2.1 创建SafetyDetectClient 并生成nonce值 

这里的nonce值会被包含在后面的检测结果里,我们要通过校验nonce值,来确定返回结果是对应我们的请求的、没有被重放攻击。要注意nonce值需满足:

l  一个nonce值只能被使用一次;

l  长度在16~66字节间;

l  建议从发送到您的服务器的数据中派生nonce值。

2.2 请求系统完整性检测接口 

1)  SysIntegrity API有两个参数:第1个参数是nonce值,可以从上一步骤获取;第2个参数是appid,可以从agconnect-services.json 文件中读取:

Ø  登录AppGallery Connect网站,-点击“我的项目”。

Ø  在项目列表中找到您的项目,在项目中点击需要配置签名证书指纹的应用。

Ø  在“项目设置 > 常规” > “应用”,可以查看。

2) 这里设定的是,用户在购买会员时,调用系统完整性检测接口,以检测支付环境是否存在风险。实际编码中,在MemberCenterAct.java类中的列表点击事件处理方法,调用SafetyDetectUtil 类的detectSysIntegrity的接口,具体代码:


  
  1. private void onAdapterItemClick(int position) {
  2. // 调用系统完整性检测接口以检测支付环境风险
  3. SafetyDetectUtil.detectSysIntegrity( this, new ICallBack<Boolean>() {
  4. @Override
  5. public void onSuccess(Boolean baseIntegrity) {
  6. if (baseIntegrity) {
  7. // 系统完整性未遭到破坏,可以继续购买
  8. buy(productInfo);
  9. } else {
  10. // 系统完整性遭到破坏,弹出提示框,来提醒用户,并让用户选择是否继续
  11. showRootTipDialog(productInfo);
  12. }
  13. }
  14. });
  15. }

3) 在商场App中,把系统完整性检测接口的调用放到SafetyDetectUtil.java这个工具类中来实现,封装在detectSysIntegrity的方法中,具体示例代码如下:


  
  1. public static void detectSysIntegrity(final Activity activity, final ICallBack<? super Boolean> callBack) {
  2. // 生成 nonce值
  3. byte[] nonce = ( "Sample" + System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8);
  4. // 从app目录下的agconnect-services.json文件中读取app_id字段
  5. String appId = AGConnectServicesConfig.fromContext(activity).getString( "client/app_id");
  6. // 获取 Safety Detect 服务客户端,调用sysIntegrity API,并添加成功事件监听
  7. SysIntegrityRequest sysintegrityrequest = new SysIntegrityRequest();
  8. sysintegrityrequest.setAppid(appId);
  9. sysintegrityrequest.setNonce(nonce);
  10. //PS256 or RS256
  11. sysintegrityrequest.setAlg( "RS256");
  12. Task task = mClient.sysIntegrity(sysintegrityrequest);
  13. task.addOnSuccessListener( new OnSuccessListener<SysIntegrityResp>() {
  14. @Override
  15. public void onSuccess(SysIntegrityResp response) {
  16. //Safety Detect 服务接口成功响应。可以通过 SysIntegrityResp 类的 getResult 方法来获取检测结果
  17. String jwsStr = response.getResult();
  18. VerifyResultHandler verifyResultHandler = new VerifyResultHandler(jwsStr, callBack);
  19. //将检测结果发送至开发者的服务器进行验证
  20. verifyJws(activity, jwsStr, verifyResultHandler);
  21. }
  22. });
  23. }

4)  这里在verifyJws 方法中请求App Server的相关接口,来对检测结果进行验证。这个方法的第3个参数是一个 VerifyResultHandler 类对象, 它实现了一个回调接口,以便在服务器验证结束后,对返回的结果进行后续的处理。接下来介绍如何在App Server中验证检测结果。

2.3 在App Server中验证检测结果

App在获得TSMS Server返回的检测结果后,将其发送到App Server,由App Server使用HUAWEI CBG根证书来对结果中的签名和证书链进行校验,从而确认本次系统完整性检测结果是否有效。

App Server侧读取证书并验证 JWS 字符串的示例代码如下:

1) 解析 JWS字符串,获取其中的 header、payload和signature


  
  1. public JwsVerifyResp verifyJws(JwsVerifyReq jwsVerifyReq) {
  2. // 获取端侧发送到服务器侧的jws信息
  3. String jwsStr = jwsVerifyReq.getJws();
  4. // 解析JWS, 分段, 该JWS固定为三段,使用"."号分隔
  5. String[] jwsSplit = jwsStr.split( "\\.");
  6. try {
  7. // 解析JWS, Base64解码, 并构造JWSObject
  8. JWSObject jwsObject = new JWSObject( new Base64URL(jwsSplit[ 0]), new Base64URL(jwsSplit[ 1]), new Base64URL(jwsSplit[ 2]));
  9. // 验证JWS并设置验证结果
  10. boolean result = VerifySignatureUtil.verifySignature(jwsObject);
  11. // 服务器侧检测结果验证响应消息体
  12. JwsVerifyResp jwsVerifyResp = new JwsVerifyResp();
  13. jwsVerifyResp.setResult(result);
  14. } catch (ParseException | NoSuchAlgorithmException e) {
  15. RUN_LOG.catching(e);
  16. }
  17. return jwsVerifyResp;
  18. }

2)  这里使用VerifySignatureUtil工具类中的verifySignature方法完成相关信息的验证,包括JWS签名算法、证书链、签名证书主机名、JWS签名等,示例代码:


  
  1. public static boolean verifySignature(JWSObject jws) throws NoSuchAlgorithmException {
  2. JWSAlgorithm jwsAlgorithm = jws.getHeader().getAlgorithm();
  3. // 1. 验证JWS签名算法
  4. if ( "RS256".equals(jwsAlgorithm.getName())) {
  5. // 进行证书链校验,并根据签名算法获取 Signature 类实例,用来验证签名
  6. return verify(Signature.getInstance( "SHA256withRSA"), jws);
  7. }
  8. return false;
  9. }
  10. private static boolean verify(Signature signature, JWSObject jws) {
  11. // 提取JWS头部证书链信息, 并转换为合适的类型, 以便进行后续操作
  12. X509Certificate[] certs = extractX509CertChain(jws);
  13. // 2. 校验证书链
  14. try {
  15. verifyCertChain(certs);
  16. } catch (Exception e) {
  17. return false;
  18. }
  19. // 3. 校验签名证书(叶子证书)域名信息, 该域名固定为sysintegrity.platform.hicloud.com
  20. try {
  21. new DefaultHostnameVerifier().verify( "sysintegrity.platform.hicloud.com", certs[ 0]);
  22. } catch (SSLException e) {
  23. return false;
  24. }
  25. // 4. 验证JWS签名信息,使用签名证书里的公钥来验证
  26. PublicKey pubKey = certs[ 0].getPublicKey();
  27. try {
  28. // 使用签名证书里的公钥初始化 Signature 实例
  29. signature.initVerify(pubKey);
  30. // 从 JWS 提取签名输入,并输入到 Signature 实例
  31. signature.update(jws.getSigningInput());
  32. // 使用Signature 实例来验证签名信息
  33. return signature.verify(jws.getSignature().decode());
  34. } catch (InvalidKeyException | SignatureException e) {
  35. return false;
  36. }
  37. }

3) 这里的extractX509CertChain方法,实现了从JWS Header中提取证书链的过程,详细代码如下:


  
  1. private static X509Certificate[] extractX509CertChain(JWSObject jws) {
  2. List<X509Certificate> certs = new ArrayList<>();
  3. List<com.nimbusds.jose.util.Base64> x509CertChain = jws.getHeader().getX509CertChain();
  4. try {
  5. CertificateFactory certFactory = CertificateFactory.getInstance( "X.509");
  6. certs.addAll(x509CertChain.stream().map(cert -> {
  7. try {
  8. return (X509Certificate) certFactory.generateCertificate( new ByteArrayInputStream(cert.decode()) );
  9. } catch (CertificateException e) {
  10. RUN_LOG. error( "X5c extract failed!");
  11. }
  12. return null;
  13. }).filter(Objects::nonNull).collect(Collectors.toList()));
  14. } catch (CertificateException e) {
  15. RUN_LOG. error( "X5c extract failed!");
  16. }
  17. return (X509Certificate[]) certs.toArray();
  18. }

4) 这里的verifyCertChain方法,实现了证书链校验的过程,具体实现如下:


  
  1. private static void verifyCertChain(X509Certificate[] certs) throws CertificateException, NoSuchAlgorithmException,
  2. InvalidKeyException, NoSuchProviderException, SignatureException {
  3. // 逐一验证证书有效期及证书的签发关系
  4. for ( int i = 0; i < certs.length - 1; ++i) {
  5. certs[i].checkValidity();
  6. PublicKey pubKey = certs[i + 1].getPublicKey();
  7. certs[i].verify(pubKey);
  8. }
  9. // 使用预置的 HUAWEI CBG 根证书, 来验证证书链中的最后一张证书
  10. PublicKey caPubKey = huaweiCbgRootCaCert.getPublicKey();
  11. certs[certs.length - 1].verify(caPubKey);
  12. }

5) 华为根证书的加载是在VerifySignatureUtil工具类的静态代码段中实现的。示例代码如下:


  
  1. static {
  2. // 加载预置的 HUAWEI CBG 根证书
  3. File filepath = "~/certs/Huawei_cbg_root.cer";
  4. try (FileInputStream in = new FileInputStream(filepath)) {
  5. CertificateFactory cf = CertificateFactory.getInstance( "X.509");
  6. huaweiCbgRootCaCert = (X509Certificate) cf.generateCertificate(in);
  7. } catch (IOException | CertificateException e) {
  8. RUN_LOG.error( "HUAWEI CBG root cert load failed!");
  9. }
  10. }

至此,我们已经在App Server侧完成了对检测结果的验证,验证通过的结果将返回给端侧进行后续业务处理。

2.4 获取系统完整性检测结果

1) 在上一步骤完成后,App就可以从payload中获取可信的系统完整性检测结果。我们在前述的VerifyResultHandler类的回调接口中,解析系统完整性检测结果,示例代码如下:


  
  1. private static final class VerifyResultHandler implements ICallBack<Boolean> {
  2. private final String jwsStr;
  3. private final ICallBack <? super Boolean> callBack;
  4. private VerifyResultHandler( String jwsStr, ICallBack <? super Boolean> callBack) {
  5. this.jwsStr = jwsStr;
  6. this.callBack = callBack;
  7. }
  8. @Override
  9. public void onSuccess( Boolean verified) {
  10. if (verified) {
  11. // 服务器侧验证通过,提取系统完整性检测结果
  12. String payloadDetail = new String(Base64.decode(jwsStr.split( "\\.")[ 1].getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE), StandardCharsets.UTF_8);
  13. try {
  14. final boolean basicIntegrity = new JSONObject(payloadDetail).getBoolean( "basicIntegrity");
  15. // 通过回调返回系统完整性检测结果
  16. callBack.onSuccess(basicIntegrity);
  17. } catch (JSONException e) {
  18. }
  19. }
  20. }
  21. }

2) 具体的检测报文的样例如下:


  
  1. {
  2. "apkCertificateDigestSha256": [
  3. "osaUtTsdAvezjQBaW3IhN3/fsc6NQ5KwKuAQXcfrxb4="
  4. ],
  5. "apkDigestSha256": "vFcmE0uw5s+4tFjXF9rVycxk2xR1rXiZFHuuBFzTVy8=",
  6. "apkPackageName": "com.example.mockthirdapp",
  7. "basicIntegrity": false,
  8. "detail": [
  9. "root",
  10. "unlocked"
  11. ],
  12. "nonce": "UjJScmEyNGZWbTV4YTJNZw==",
  13. "timestampMs": 1604048377137,
  14. "advice": "RESTORE_TO_FACTORY_ROM"
  15. }

3) 当检测结果中basicIntegrity字段为false时,表示存在风险,App就可以对用户作风险提示。

结后语

官网开发指南,各位小伙伴们可以自行查阅参考。除了系统完整性检测(SysIntegrity),还有其他4个功能的代码,都是支持Java/Kotlin两种开发语言:华为官网的示例代码Java/Kotlin,下载后,根据提示说明进行操作就可运行。

 

 

>>访问华为开发者联盟官网,了解更多相关内容

>>获取开发指导文档

>>华为移动服务开源仓库地址:GitHubGitee

关注我们,第一时间了解华为移动服务最新技术资讯~


转载:https://blog.csdn.net/HUAWEI_HMSCore/article/details/113752581
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场