在這篇文章你能看到對(duì)安卓本地保存密鑰的實(shí)踐
前言
在網(wǎng)絡(luò)傳輸過(guò)程中,我們往往需要一個(gè)密鑰對(duì)參數(shù)進(jìn)行簽名,用于驗(yàn)證來(lái)源可靠,所以我們?cè)赼pp打包過(guò)程中,就避免不了在app中保存此密鑰。
保存密鑰的方法
直接在java代碼中寫
最基本簡(jiǎn)單的就是直接在java代碼把密鑰串寫在靜態(tài)變量中,最簡(jiǎn)單,顯然也是不太靠譜的,容易反編譯后被發(fā)現(xiàn),即使混淆后,這種靜態(tài)變量也是容易被發(fā)現(xiàn)的。
寫在cpp里
寫在cpp里,打包后,保存在so庫(kù)中,這個(gè)方法,安全度增加了很多,編譯后的c代碼,反編譯非常困難,看起來(lái)美美的
Java_com_yglx_testjni_MainActivity_getKey(
JNIEnv *env,
jobject /* this */) {
std::string key = "asdkjflaksdjflksjadfasdfasdfasdfasdfsdfasdlfkjasldfjasdlf";
return env->NewStringUTF(key.c_str());
}
看起來(lái)不錯(cuò),但是又有問(wèn)題了,當(dāng)把a(bǔ)pk解壓后,lib里面可以看到生成的so文件,別人就可以拿到這個(gè)so文件,之后新建一個(gè)相同包名和類名的應(yīng)用,這樣就可以拿到你隱藏的密鑰
了,那能不能在被有心之人拿到so文件的情況下,仍舊不能獲取到密鑰呢,那就是接下來(lái)策略,執(zhí)行代碼前先校驗(yàn)app簽名。
cpp里加入應(yīng)用的簽名校驗(yàn)
獲取應(yīng)用的簽名,實(shí)際也是通過(guò)android中java的api進(jìn)行獲取的,我把部分代碼貼出。
extern "C"
JNIEXPORT jstring JNICALL
Java_com_yglx_testjni_MainActivity_getSafeKey(JNIEnv *env, jobject instance,jobject contextObject) {
jmethodID getPackageManagerId = (env)->GetMethodID(contextClass, "getPackageManager","()Landroid/content/pm/PackageManager;");
jmethodID getPackageNameId = (env)->GetMethodID(contextClass, "getPackageName","()Ljava/lang/String;");
jmethodID signToStringId = (env)->GetMethodID(signatureClass, "toCharsString","()Ljava/lang/String;");
jmethodID getPackageInfoId = (env)->GetMethodID(packageNameClass, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jobject packageManagerObject = (env)->CallObjectMethod(contextObject, getPackageManagerId);
jstring packNameString = (jstring)(env)->CallObjectMethod(contextObject, getPackageNameId);
jobject packageInfoObject = (env)->CallObjectMethod(packageManagerObject, getPackageInfoId,packNameString, 64);
jfieldID signaturefieldID =(env)->GetFieldID(packageInfoClass,"signatures", "[Landroid/content/pm/Signature;");
jobjectArray signatureArray = (jobjectArray)(env)->GetObjectField(packageInfoObject, signaturefieldID);
jobject signatureObject = (env)->GetObjectArrayElement(signatureArray,0);
const char* signStrng = (env)->GetStringUTFChars((jstring)(env)->CallObjectMethod(signatureObject, signToStringId),0);
if(strcmp(signStrng,RELEASE_SIGN)==0)//簽名一致 返回合法的 api key,否則返回錯(cuò)誤
{
return (env)->NewStringUTF(AUTH_KEY);
}else
{
return (env)->NewStringUTF("error");
}
}
到這里,使用cpp并且用校驗(yàn)應(yīng)用簽名的方法就能達(dá)到一個(gè)對(duì)密鑰的比較好的保護(hù)。