爪哇 .class 文件可以相当容易地反编译。如果我必须在代码中使用登录数据,如何保护我的数据库?

有帮助吗?

解决方案

切勿将密码硬编码到您的代码中。这是最近在 25 个最危险的编程错误:

对于熟练的反向工程师而言,将秘密帐户和密码硬编码非常方便。如果您的所有软件中的密码都相同,那么当该密码不可避免地成为已知时,每个客户都会变得脆弱。而且因为它是硬编码的,所以修复是一个巨大的痛苦。

您应该将配置信息(包括密码)存储在应用程序启动时读取的单独文件中。这是防止密码因反编译而泄漏的唯一真正方法(永远不要将其编译到二进制文件中)。

有关此常见错误的更多信息,您可以阅读 CWE-259 文章. 。本文包含更详尽的定义、示例以及有关该问题的许多其他信息。

在 Java 中,最简单的方法之一是使用 Preferences 类。它旨在存储各种程序设置,其中一些可能包括用户名和密码。

import java.util.prefs.Preferences;

public class DemoApplication {
  Preferences preferences = 
      Preferences.userNodeForPackage(DemoApplication.class);

  public void setCredentials(String username, String password) {
    preferences.put("db_username", username);
    preferences.put("db_password", password);
  }

  public String getUsername() {
    return preferences.get("db_username", null);
  }

  public String getPassword() {
    return preferences.get("db_password", null);
  }

  // your code here
}

在上面的代码中,您可以调用 setCredentials 显示询问用户名和密码的对话框后的方法。当需要连接数据库时,直接使用 getUsernamegetPassword 检索存储值的方法。登录凭据不会被硬编码到您的二进制文件中,因此反编译不会带来安全风险。

重要的提示: 首选项文件只是纯文本 XML 文件。确保采取适当的步骤来防止未经授权的用户查看原始文件(UNIX 权限、Windows 权限等)。至少在 Linux 中,这不是问题,因为调用 Preferences.userNodeForPackage 将在当前用户的主目录中创建 XML 文件,无论如何其他用户都无法读取该文件。在 Windows 中,情况可能有所不同。

更重要的注意事项: 在这个答案和其他人的评论中,关于这种情况的正确架构是什么进行了很多讨论。原来的问题并没有真正提到应用程序的使用上下文,所以我将谈谈我能想到的两种情况。第一种情况是使用该程序的人已经知道(并且被授权知道)数据库凭据。第二种情况是,您(开发人员)试图对使用该程序的人保密数据库凭据。

第一个案例:用户有权知道数据库登录凭据

在这种情况下,我上面提到的解决方案将起作用。爪哇 Preference 类将以纯文本形式存储用户名和密码,但首选项文件只能由授权用户读取。用户只需打开首选项 XML 文件并读取登录凭据,但这并不存在安全风险,因为用户一开始就知道凭据。

第二种情况:试图对用户隐藏登录凭据

这是更复杂的情况:用户不应知道登录凭据,但仍需要访问数据库。在这种情况下,运行应用程序的用户可以直接访问数据库,这意味着程序需要提前知道登录凭据。我上面提到的解决方案不适合这种情况。您可以将数据库登录凭据存储在首选项文件中,但用户将能够读取该文件,因为他们将是所有者。事实上,确实没有什么好的方法可以安全地使用这种情况。

正确案例:使用多层架构

正确的方法是在数据库服务器和客户端应用程序之间建立一个中间层,用于对单个用户进行身份验证并允许执行一组有限的操作。每个用户都有自己的登录凭据,但没有数据库服务器的登录凭据。凭证将允许访问中间层(业务逻辑层),并且对于每个用户来说都是不同的。

每个用户都有自己的用户名和密码,这些用户名和密码可以本地存储在首选项文件中,而不存在任何安全风险。这被称为 三层架构 (这些层是数据库服务器、业务逻辑服务器和客户端应用程序)。它更复杂,但它确实是执行此类操作的最安全方法。

基本操作顺序是:

  1. 客户端使用用户的个人用户名/密码向业务逻辑层进行身份验证。用户名和密码是用户已知的,并且与数据库登录凭据没有任何关系。
  2. 如果身份验证成功,客户端会向业务逻辑层发出请求,要求从数据库中获取一些信息。例如,产品库存。请注意,客户端的请求不是 SQL 查询;它是一个远程过程调用,例如 getInventoryList.
  3. 业务逻辑层连接到数据库并检索所请求的信息。业务逻辑层负责根据用户的请求形成安全的SQL查询。SQL 查询的任何参数都应该被清理以防止 SQL 注入攻击。
  4. 业务逻辑层将库存列表发送回客户端应用程序。
  5. 客户端向用户显示库存列表。

需要注意的是,在整个过程中, 客户端应用程序从不直接连接到数据库. 。业务逻辑层接收来自经过身份验证的用户的请求,处理客户端对库存列表的请求,然后才执行 SQL 查询。

其他提示

把密码输入到应用程序将读取的文件。在源文件中从不嵌入密码。周期。

Ruby有称为 DBI :: DBRC 以这样的使用一个鲜为人知的模块。我毫不怀疑,Java有一个等价的。无论如何,这是不难写一个。

无论您做什么,敏感信息都会存储在某个文件中。你的目标是让它尽可能地难以获得。您能实现多少取决于您的项目、需求和公司的资金实力。

最好的方法是不要在任何地方存储任何密码。这是通过使用哈希函数生成和存储密码哈希来实现的:

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366

哈希算法是一种单向函数。他们将任何数量的数据变成无法逆转的固定长度“指纹”。他们还具有这样的属性,即如果输入甚至很小,则产生的哈希完全不同(请参见上面的示例)。这对于保护密码非常有用,因为即使密码文件本身受到损害,我们也希望以保护它们的形式存储密码,但与此同时,我们需要能够验证用户的密码是否正确。

不相关的注释: 在过去的互联网时代,当您单击“忘记密码”链接时,网站会通过电子邮件向您发送纯文本密码。他们可能将它们存储在某个数据库中。当黑客获得对其数据库的访问权限时,他们将获得所有密码。由于许多用户会在多个网站上使用相同的密码,因此这是一个巨大的安全问题。幸运的是,如今这并不常见。

现在问题来了:存储密码的最佳方式是什么?我会考虑 this(身份验证和用户管理服务stormpath的) 解决方案是一个非常理想的解决方案:

  1. 您的用户输入凭据,这是根据密码哈希进行验证的
  2. 生成并存储密码哈希值,而不是密码
  3. 哈希执行多次
  4. 哈希值是使用随机生成的盐生成的
  5. 哈希值使用私钥加密
  6. 私钥存储在与哈希值不同的物理位置
  7. 私钥以基于时间的方式更新
  8. 加密的哈希值被分成块
  9. 这些块存储在物理上独立的位置

显然你不是谷歌或银行,所以这对你来说是一个过度的解决方案。但随之而来的问题是:您的项目需要多少安全性,您有多少时间和金钱?

对于许多应用程序来说,尽管不推荐,但在代码中存储硬编码密码可能是一个足够好的解决方案。但是,通过从上面的列表中轻松添加几个额外的安全步骤,您可以使您的应用程序更加安全。

例如,假设步骤 1 不是您的项目可接受的解决方案。您不希望用户每次都输入密码,或者您甚至不希望/不需要用户知道密码。但您仍然在某处拥有敏感信息,并且您希望保护这些信息。您有一个简单的应用程序,没有服务器来存储您的文件,否则这对您的项目来说太麻烦了。您的应用程序在无法安全存储文件的环境中运行。这是最糟糕的情况之一,但仍然通过一些额外的安全措施,您可以获得更安全的解决方案。例如,您可以将敏感信息存储在文件中,并且可以加密该文件。您可以将加密私钥硬编码在代码中。您可以混淆代码,从而使其他人更难破解它。有许多库用于此目的,请参阅 这个链接. 。(我想再次警告您,这并不是 100% 安全的。拥有正确知识和工具的聪明黑客可以破解此问题。但根据您的要求和需求,这可能对您来说是一个足够好的解决方案)。

这个问题显示了如何存储密码和其它数据以加密的文件:爪哇256位AES基于密码的加密

MD5是一个散列算法,而不是一个加密算法,在短ü不能取回笏ü散列中,u只能比较。 存储用户的认证信息,而不是数据库的用户名和密码时,最好应使用。 分贝的用户名和pwd应该被加密,并保存在一个配置文件,这样做至少

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top