Ionic签名校验验证
1. 为什么要进行签名校验2. 查看安卓证书信息3. 编写检验文件3.1 编写校验文件`SignCheck.java`3.2 修改MainActivity.java3.3 其他方案
4. 打包4.1 移除android平台4.2 增加android平台版本4.3 覆盖`MainActivity.java`4.4 使用证书进行打包
5. 打包完成安装apk6. 加固原理
1. 为什么要进行签名校验
有些应用会使用工具对应用进行扫描进行判断所存在的风险,特别一些国企,金融,安全类等应用,其中扫描有一项是应用签名未校验风险。
危害的风险描述: 签名证书是对App开发者身份的唯一标识,开发者可利用签名证书有效降低App的盗版率,。未进行签名证书的App,可能被反编译后进行二次打包。重新打包签名的应用,可能导致App被仿冒盗版,影响其合法收入,甚至可能被添钓鱼代码、病毒代码、恶意代码,导致用户敏感信息泄露或者恶意攻击。
因此针对这个需求需要对应用进行处理,可以检测App程序启动时是否校验签名证书。增加签名证书的校验代码,降低App被二次打包的几率。
通常会对应用进行几步操作: 1.增加签名校验。 2.对App进行加固。3.对加固的App进行二次签名。
2. 查看安卓证书信息
Ionic移动开发完成后,需要进行打包操作,此时需要使用证书进行打包。
证书可以自己进行生成。那如何查看证书生成后的信息呢?
keytool -list -v -keystore mykeystorefile
(证书名称
)
钥库类型: JKS
密钥库提供方: SUN
您的密钥库包含 1 个条目
别名: com.zhangguoye.app
创建日期: 2018-1-26
条目类型: PrivateKeyEntry
证书链长度: 1
证书
[1
]:
所有者: CN
=com.zhangguoye.app, OU
=com.zhangguoye.app, O
=com.zhangguoye.app
发布者: CN
=com.zhangguoye.app, OU
=com.zhangguoye.app, O
=com.zhangguoye.app
序列号: 1230f945
有效期开始日期: Tue Feb 26 15:04:52 CST 2018, 截止日期: Sat Feb 20 15:04:52 CST 2020
证书指纹:
MD5: 12:34:56:68:6A:78:22:90:12:FE:12:95:12F:6E:29:12
SHA1: 12:23:45:E1:D1:01:A2:12:37:B2:E3:B1:79:21:16:FD:0B:8D:3E:EB
SHA256: 12:10:37:15:73:D1:11:F1:32:23:33:63:12:9A:12:12:ED:12:12:12:12:2D:02:12:22:4A:52:62:92:51:22:01
签名算法名称: S*********
版本: 3
扩展:
.....
*******************************************
*******************************************
3. 编写检验文件
3.1 编写校验文件SignCheck.java
package com
.zhangguoye
.app
;
import android
.app
.AlertDialog
;
import android
.content
.Context
;
import android
.content
.pm
.PackageInfo
;
import android
.content
.pm
.PackageManager
;
import android
.content
.pm
.Signature
;
import android
.content
.DialogInterface
;
import android
.util
.Log
;
import java
.io
.ByteArrayInputStream
;
import java
.io
.InputStream
;
import java
.security
.MessageDigest
;
import java
.security
.NoSuchAlgorithmException
;
import java
.security
.cert
.CertificateEncodingException
;
import java
.security
.cert
.CertificateFactory
;
import java
.security
.cert
.X509Certificate
;
public class SignCheck {
private Context context
;
private String cer
= null
;
private String realCer
= null
;
private static final String TAG
= "SignCheck";
public SignCheck(Context context
) {
this.context
= context
;
this.cer
= getCertificateSHA1Fingerprint();
}
public SignCheck(Context context
, String realCer
) {
this.context
= context
;
this.realCer
= realCer
;
this.cer
= getCertificateSHA1Fingerprint();
}
public String
getRealCer() {
return realCer
;
}
public void setRealCer(String realCer
) {
this.realCer
= realCer
;
}
public String
getCertificateSHA1Fingerprint() {
PackageManager pm
= context
.getPackageManager();
String packageName
= context
.getPackageName();
int flags
= PackageManager
.GET_SIGNATURES
;
PackageInfo packageInfo
= null
;
try {
packageInfo
= pm
.getPackageInfo(packageName
, flags
);
} catch (PackageManager.NameNotFoundException e
) {
e
.printStackTrace();
}
Signature
[] signatures
= packageInfo
.signatures
;
byte[] cert
= signatures
[0].toByteArray();
InputStream input
= new ByteArrayInputStream(cert
);
CertificateFactory cf
= null
;
try {
cf
= CertificateFactory
.getInstance("X509");
} catch (Exception e
) {
e
.printStackTrace();
}
X509Certificate c
= null
;
try {
c
= (X509Certificate
) cf
.generateCertificate(input
);
} catch (Exception e
) {
e
.printStackTrace();
}
String hexString
= null
;
try {
MessageDigest md
= MessageDigest
.getInstance("SHA1");
byte[] publicKey
= md
.digest(c
.getEncoded());
hexString
= byte2HexFormatted(publicKey
);
} catch (NoSuchAlgorithmException e1
) {
e1
.printStackTrace();
} catch (CertificateEncodingException e
) {
e
.printStackTrace();
}
return hexString
;
}
private String
byte2HexFormatted(byte[] arr
) {
StringBuilder str
= new StringBuilder(arr
.length
* 2);
for (int i
= 0; i
<arr
.length
; i
++) {
String h
= Integer
.toHexString(arr
[i
]);
int l
=h
.length();
if (l
== 1)
h
= "0" + h
;
if (l
> 2)
h
= h
.substring(l
- 2, l
);
str
.append(h
.toUpperCase());
if (i
< (arr
.length
- 1))
str
.append(':');
}
return str
.toString();
}
public boolean check() {
if (this.realCer
!= null
) {
cer
= cer
.trim();
realCer
= realCer
.trim();
if (this.cer
.equals(this.realCer
)) {
return true;
}
}else {
Log
.e(TAG
, "未给定真实的签名 SHA-1 值");
}
return false;
}
public void checkSuccess() {
new AlertDialog.Builder(context
)
.setTitle("签名校验成功")
.setMessage("成功!")
.setPositiveButton("确定", null
)
.show();
}
public void showCheckErrorTips() {
new AlertDialog.Builder(context
)
.setTitle("签名校验失败")
.setMessage("存在签名异常,请在官方下载最新的APP!http://zhangguoye.com")
.setCancelable(false)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog
, int which
) {
System
.exit(0);
}
})
.show();
}
}
3.2 修改MainActivity.java
修改MainActivity.java,增加检验签名方法
package com
.zhangguoye
.app
;
import android
.content
.Intent
;
import android
.os
.Bundle
;
import android
.text
.TextUtils
;
import android
.util
.Base64
;
import org
.apache
.cordova
.*
;
import java
.io
.UnsupportedEncodingException
;
public class MainActivity extends CordovaActivity {
public static String param
= "";
@Override
public void onCreate(Bundle savedInstanceState
) {
super.onCreate(savedInstanceState
);
singCheck();
}
private void singCheck() {
SignCheck signCheck
= new SignCheck(this, "12:23:45:E1:D1:01:A2:12:37:B2:E3:B1:79:21:16:FD:0B:8D:3E:EB");
if (signCheck
.check()) {
} else {
signCheck
.showCheckErrorTips();
}
}
}
3.3 其他方案
可以编写安卓的方法,通过ionic层使用javascript调用进行通信,同样实现运行时进行签名的校验。 可以封装成签名校验的cordova插件,供ionic项目进行使用。
4. 打包
4.1 移除android平台
ionic cordova platform
rm android
4.2 增加android平台版本
ionic cordova platform add android
若需要指定版本则
ionic cordova platform add android@6.5.0
4.3 覆盖MainActivity.java
在目录下找到此文件并覆盖 platforms/android/src/com/zhangguoye 因为目录可能跟你的不同,你可以直接在项目里搜索此文件进行覆盖
在MainActivity.java当前目录加入文件SignCheck.java
4.4 使用证书进行打包
ionic cordova build android --device --minifycss --minfyjs --optimizejs --prod --release -- -- --keystore
=./certification/keystore/zhangguoye --alias
=com.zhangguoye.app
注意keystore=./certification/keystore/zhangguoye --alias=com.zhangguoye.app 这一段是配置成你自己的证书路径和证书名称、证书别名
5. 打包完成安装apk
打包完成,安装apk并启动。 此时若是App被人使用其他证书进行二次签名后,会有对应的提示。 确定后会关闭APP
6. 加固原理
这里有一篇介绍安卓加固的原理文章,可了解下: https://www.cnblogs.com/my-testing-life/articles/12613496.html