我正在尝试使用签名证书在运行时生成令牌,并在服务器上验证该令牌以访问任何资源。我不想将令牌存储在XML文件中,因为它在APK逆向工程后可用
生成令牌的代码是
public String getToken() {
Signature[] sigs;
try {
sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
String token = sigs[0].toCharsString();
return token;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
问题是某些设备返回不同的令牌,即使apk是从同一证书生成的,也不知道为什么它为某些设备返回不同的令牌。
我想要的只是生成一个可用于访问 Web 资源的令牌,我不想将令牌存储在 apk 中,没有人可以通过反编译 apk 来获取令牌。
您可以使用C或C++存储令牌 并添加签名验证
public static String getSignature(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
return signatures[0].toCharsString();
} catch(PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
const char * app_signature = "singsing";
static int is_valid = 0;
void
Java_com_xxx_xxx_nativeInit(JNIEnv *env, jobject thiz, jobject context_object){
jclass context_class = (*env)->GetObjectClass(env, context_object);
//context.getPackageManager()
jmethodID methodId = (*env)->GetMethodID(env, context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject package_manager_object = (*env)->CallObjectMethod(env, context_object, methodId);
if (package_manager_object == NULL) {
return;
}
//context.getPackageName()
methodId = (*env)->GetMethodID(env, context_class, "getPackageName", "()Ljava/lang/String;");
jstring package_name_string = (jstring)(*env)->CallObjectMethod(env, context_object, methodId);
if (package_name_string == NULL) {
return ;
}
(*env)->DeleteLocalRef(env,context_class);
//PackageManager.getPackageInfo(Sting, int)
//public static final int GET_SIGNATURES= 0x00000040;
jclass pack_manager_class = (*env)->GetObjectClass(env, package_manager_object);
methodId = (*env)->GetMethodID(env, pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
(*env)->DeleteLocalRef(env,pack_manager_class);
jobject package_info_object = (*env)->CallObjectMethod(env, package_manager_object, methodId, package_name_string, 0x40);
if (package_info_object == NULL) {
return ;
}
(*env)->DeleteLocalRef(env,package_manager_object);
//PackageInfo.signatures[0]
jclass package_info_class = (*env)->GetObjectClass(env, package_info_object);
jfieldID fieldId = (*env)->GetFieldID(env, package_info_class, "signatures", "[Landroid/content/pm/Signature;");
(*env)->DeleteLocalRef(env,package_info_class);
jobjectArray signature_object_array = (jobjectArray)(*env)->GetObjectField(env,package_info_object, fieldId);
if (signature_object_array == NULL) {
return ;
}
jobject signature_object = (*env)->GetObjectArrayElement(env,signature_object_array, 0);
(*env)->DeleteLocalRef(env,package_info_object);
jclass signature_class = (*env)->GetObjectClass(env, signature_object);
methodId = (*env)->GetMethodID(env, signature_class, "toCharsString", "()Ljava/lang/String;");
(*env)->DeleteLocalRef(env,signature_class);
jstring signature_jstirng = (jstring) (*env)->CallObjectMethod(env, signature_object, methodId);
const char *sign=(*env)->GetStringUTFChars(env, signature_jstirng,NULL);
if (strcmp(sign,app_signature)==0 || strcmp(sign,app_j_s)==0) {
is_valid= 1;
}
return;
}
签名证书的指纹在所有设备上都是唯一的。您是否请尝试此解决方案以将该指纹作为字符串并将其用作令牌。
https://stackoverflow.com/a/22506133/4586742
@Om Infowave Developers,
我建议您使用Android密钥库系统 以生成密钥对,然后使用密钥对加密令牌,将令牌存储在共享首选项中。每当需要令牌解密令牌时,请使用密钥对。
- 这样,您每次都会获得唯一的令牌。
- 令牌是加密和保护的。
- 密钥对对于每个设备都是不同的,因此更安全。
另外,我只是注意到您返回了基于零索引的键。它们可能是您正在寻找的关键出现在后续索引中的机会。建议您记录存储在Signature[] sigs
中的所有密钥;
希望这有帮助。