我有一个休息服务器,我只希望我的应用程序能够与我的REST服务器通信。即如果有人将网址放入浏览器中,他们将无法与我的服务器进行通信
目前我正在考虑将我的密钥哈希作为额外参数添加到我的请求调用上,然后存储密钥
哈希不存储在我的应用程序中,但会使用以下方法自动检索。
public static void getHashes(Activity act) {
PackageInfo info;
try {
info = act.getPackageManager().getPackageInfo("com.my.package.myapp", PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String something = new String(Base64.encode(md.digest(), 0));
//String something = new String(Base64.encodeBytes(md.digest()));
Log.i("hash key", something);
}
} catch (NameNotFoundException e1) {
Log.e("name not found", e1.toString());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm", e.toString());
} catch (Exception e) {
Log.e("exception", e.toString());
}
}
我将这个方法只调用一次,例如在某个时间,以便我可以在logcat上看到它并在我编译到生产apk后将其保存到我的服务器。这意味着它不会再被任何其他人看到了。
我会将此密钥存储在我的服务器上,我的应用程序会在每次发出请求时发送此密钥。如果密钥不同,那么我的服务器将不会响应。
这种方法安全吗?谁能看到它的缺陷?
答案 0 :(得分:0)
不,这不安全。
攻击者可以观察到在请求中发送的此哈希的单个实例,然后将其包含在他们自己的请求中,您的服务器将无法区分。例如,哈希可以由第一个人在网上发布以获得它。
但是,这不仅仅是您的方法存在的问题:没有已知的一般问题的安全解决方案,请参阅this answer进行更全面的讨论(在上下文中) WCF而不是Android,但参数相同)。
答案 1 :(得分:0)
不,您需要首先向服务器询问挑战,然后返回应用密钥的散列值,该挑战,消息本身的内容(签名除外)以及两者都知道的一些随机字节数组应用程序和服务器端。如果以这种方式完成,应该免于网络嗅探,重放攻击并且还尝试使用合法应用程序作为消息模板生成器(有效身份验证,其他内容可能被替换)。您也可以以相同的方式验证服务器端。
不幸的是,在.apk文件落入攻击者手中后,几乎没有什么可以对你的应用程序进行逆向工程。然而,谷歌和亚马逊的应用程序商店提供了一些防止获取.apk进行反汇编的保护。