是的,这是一个非常笼统的问题,但我想了解处理与向应用程序提供敏感数据的Web服务器接触的最佳方式。任何链接、一般信息、建议等都将不胜感激。
由于应用程序将存储从数据库检索的持久数据一段时间... 一切都变得有些棘手。
这要取决于你的受众。通常,Android操作系统通过经过验证的Linux文件权限禁止应用程序访问彼此的文件(即数据库、首选项文件、存储在应用程序私有目录中的常规文件)。然而,在已获取root权限的设备上,应用程序可以获得root访问权限并读取所有内容。以下是需要考虑的几个问题:
总之,如果你的信息不是非常敏感(例如信用卡信息),我建议仅使用Android提供的默认安全性(即保存所有内容以纯文本形式,知道其他应用程序无法访问它)。
否则,加密是最好的方法。它不是100%安全的(黑客可能会反编译你的应用程序并找出如何解密数据),但很难被破解,并且会阻止大多数黑客。特别是如果你使用像ProGuard这样的代码混淆工具。
你有几个选择。首先,始终使用HTTPS。启用HTTPS后,以下是我建议采取的两种额外的安全措施:
time = 1321802432&key = [generated-key]
generated-key
从 time
参数生成。例如: md5(time + salt)
。当服务器收到此请求时,它可以执行以下两个操作:
key
是否确实等于 md5(time + salt)
(请注意,只有客户端和服务器知道salt,它可以类似地混淆API密钥以上),以及 time
是否不太过去(例如,如果它比过去的1-2分钟更长,则将请求视为无效)。如果您还要进行普通HTTP请求,则第二种方法更有用,因为每个人都可以看到被发送的参数。此外,从反编译的代码中找出它要困难得多。特别是如果您在多个类中分散密钥计算逻辑。
然而,请注意没有什么事情是完全不可能破解你的应用程序的。 无论您多么混淆,如果黑客真的决心获取您的数据,他将通过反编译应用程序并花费许多不眠之夜浏览您的代码并弄清楚请求如何形成来实现此目的。保护数据的唯一真正方法是要求用户提供密码,在执行我上面写的所有工作之外。您无法从反编译的代码中获得仅存在于某人(用户)头脑中的密码:)。
(通过谷歌搜索来到这里)
我最近一直在研究这个问题,而且通过谷歌和必应搜索很多次都跳转到了这个页面。目前存储设备上数据的广泛接受方式是使用强加密算法如AES进行安全保护。但是更困难的问题是,“AES需要一个安全密钥,你该如何处理这个密钥?”
谷歌最近宣布了一种面向应用程序的云存储解决方案,因此如果情况允许,您可以考虑将密钥存储在那里。否则,好像将密钥从设备外部获取(例如在服务器上)会更好。如果可以让用户输入PIN码,那么这实际上是最好的方法。可以使用密码推导技术来存储密码,并可以重新进行推导以验证密码。
如果没有“用户输入PIN码”这部分,我没有找到太多好的答案。但是,如果您必须在应用程序中存储密钥,请不要硬编码密钥。至少,要使用安全的密码生成器和/或类似PBKDF2(基于密码的推导函数2)的推导函数来生成密钥。
如果我正确阅读了帖子,谷歌确实说过一种方法是在应用程序第一次启动时生成一个密钥,通过MODE_PRIVATE标志将密钥存储到许多文件I/O操作中,并将其用作密钥。您还可以基于该主密钥派生其他密钥,NIST实际上建议采用这种方法之类的东西。
是否信任主密钥方法,我留给您自己判断。这个密钥将在root设备上暴露出来。我也承认我仍在研究这个问题。
public String androidId = "";
private String INIT_VECTOR = "encryptionIntVec";
public String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(androidId.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeToString(encrypted, Base64.DEFAULT);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String decrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(androidId.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decode(value, Base64.DEFAULT));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public void saveSecureData(String sdt) {
SharedPreferences settings = getApplicationContext().getSharedPreferences("TableName", 0);
SharedPreferences.Editor editor = settings.edit();
String encryptedString = encrypt(sdt);
editor.putString("FieldName", encryptedString.toString());
editor.apply();
}
public String readSecureData() {
SharedPreferences settings = getApplicationContext().getSharedPreferences("TableName", 0);
String homeScore = settings.getString("FieldName", "DEFAULT");
return homeScore;
}
public void testUnit() {
androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
String lastRecord = readSecureData();
if (lastRecord.equals("DEFAULT")) {
saveSecureData("Data to save...");
} else {
String decryptedString = decrypt(lastRecord);
Toast.makeText(MainActivity.this, lastRecord + " > " + decryptedString, Toast.LENGTH_LONG).show();
}
}
androidId是一个随机生成的唯一代码,在设备首次启动时仅生成一次...
androidId
的安全? - hldev如果您想确保用户除了通过查看您的应用程序外无法看到数据,那么加密确实是唯一的方法。即使是“受保护”的存储也可以在设备被root的情况下被用户访问。即使加密也不是完全安全的,因为您需要在某个时候解密数据以便显示它。您将会阻止普通浏览者,但无法阻止决心强烈的黑客。
使用HTTPS上的SSL来传输数据,而不是HTTP,您需要在Web服务器上设置证书,但不太确定它是如何工作的。
如果您真的关心数据安全,则可以在发送之前使用独特的算法进一步加密它,并在到达应用程序时进行解密。我想这就是全部了...除非您需要更强大的保护,那么可以基于TCP开发自己的协议和/或使用另一个端口...也许这会有所帮助。
http://en.wikipedia.org/wiki/Secure_Sockets_Layer http://developer.android.com/reference/javax/net/ssl/package-summary.html http://blog.synyx.de/2010/06/android-and-self-signed-ssl-certificates/
关于在应用程序中存储数据,您可以在存储之前加密数据,或者使用其他格式而不是SQLite以获得更好的安全性,因为您可以很容易地使用浏览器查看SQLite数据库。