Java 如何保护MySQL用户名和密码不被反编译?

Java 如何保护MySQL用户名和密码不被反编译?,java,mysql,security,reverse-engineering,decompiling,Java,Mysql,Security,Reverse Engineering,Decompiling,Java.class文件可以相当容易地反编译。如果必须使用代码中的登录数据,如何保护数据库?将密码放入应用程序将读取的文件中。永远不要在源文件中嵌入密码。句号 Ruby有一个鲜为人知的模块用于这种用途。我毫不怀疑Java有一个等价物。无论如何,编写一个密码并不困难。永远不要在代码中硬编码密码。这是最近在下列会议上提出的: 硬编码一个秘密帐户和 输入软件的密码是 非常方便--对于熟练的 逆向工程师。如果密码是 你所有的软件都是一样的, 然后每个客户都会变得脆弱 当密码不可避免地变成 知道。因为它是

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

将密码放入应用程序将读取的文件中。永远不要在源文件中嵌入密码。句号


Ruby有一个鲜为人知的模块用于这种用途。我毫不怀疑Java有一个等价物。无论如何,编写一个密码并不困难。

永远不要在代码中硬编码密码。这是最近在下列会议上提出的:

硬编码一个秘密帐户和 输入软件的密码是 非常方便--对于熟练的 逆向工程师。如果密码是 你所有的软件都是一样的, 然后每个客户都会变得脆弱 当密码不可避免地变成 知道。因为它是硬编码的, 这是一个巨大的痛苦来修复

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

有关此常见错误的更多信息,请阅读。这篇文章包含了一个更全面的定义、示例以及关于这个问题的许多其他信息

在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
方法。当需要连接到数据库时,只需使用
getUsername
getPassword
方法检索存储的值。登录凭据不会硬编码到二进制文件中,因此反编译不会带来安全风险

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

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

第一种情况:用户有权知道数据库登录凭据

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

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

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

正确案例:使用多层体系结构

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

每个用户都有自己的用户名和密码,可以本地存储在首选项文件中,而不存在任何安全风险。这称为a(层是您的数据库服务器、业务逻辑服务器和客户机应用程序)。它更复杂,但它确实是做这类事情最安全的方式

基本操作顺序是:

  • 客户端使用用户的个人用户名/密码与业务逻辑层进行身份验证。用户名和密码是用户已知的,与数据库登录凭据没有任何关系
  • 如果身份验证成功,客户机将向业务逻辑层发出请求,要求从数据库中获取一些信息。例如,产品清单。注意,客户机的请求不是SQL查询;它是一个远程过程调用,例如
    getInventoryList
  • 业务逻辑层连接到数据库并检索请求的信息。业务逻辑层负责根据用户的请求形成安全的SQL查询。应清除SQL查询的任何参数,以防止SQL注入攻击
  • 业务逻辑层将库存列表发送回客户机应用程序
  • 客户端向用户显示库存列表
  • 请注意,我
    hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
    hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366