如何保护MySQL的用户名和密码免于反编译?
Java .class
文件可以很容易地反编译。 如果我必须在代码中使用login数据,如何保护我的数据库?
切勿将密码硬编码到您的代码中。 这是最近在“ 25个最危险的编程错误”中提出的 :
将密码和密码硬编码到您的软件中非常方便 – 对于熟练的反向工程师。 如果所有软件的密码都相同,那么当密码不可避免地变为已知时,每个客户都会变得脆弱。 而且因为它是硬编码的,所以修复是一个巨大的痛苦。
应该将configuration信息(包括密码)存储在应用程序启动时读取的单独文件中。 这是防止密码因反编译而泄漏的唯一方法(从不将它编译到二进制文件中)。
有关这种常见错误的更多信息,请阅读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
方法。 当您需要连接到数据库时,您可以使用getUsername
和getPassword
方法来检索存储的值。 login凭证不会被硬编码到您的二进制文件中,所以反编译不会造成安全风险。
重要说明:首选项文件只是纯文本的XML文件。 确保您采取适当措施防止未经授权的用户查看原始文件(UNIX权限,Windows权限等)。 在Linux中,至less这不是问题,因为调用Preferences.userNodeForPackage
将在当前用户的主目录中创buildXML文件,而其他用户无法读取该文件。 在Windows中,情况可能会有所不同。
更重要的注意事项:在这个答案和其他人关于什么是正确的架构是这种情况的意见,已经有很多讨论。 原来的问题并没有真正提到应用程序的使用环境,所以我会谈谈我能想到的两种情况。 第一种情况是使用程序的人已经知道(并被授权知道)数据库凭证。 第二种情况是开发人员试图将数据库凭据与使用该程序的人员保密。
第一种情况:用户有权知道数据库login凭证
在这种情况下,我上面提到的解决scheme将起作用。 Java Preference
类将以纯文本forms存储用户名和密码,但首选项文件只能由授权用户读取。 用户可以简单地打开首选项XML文件并阅读login凭证,但这不是安全风险,因为用户知道开始的凭证。
第二种情况:试图隐藏用户的login凭据
这是更复杂的情况:用户不应该知道login凭据,但仍然需要访问数据库。 在这种情况下,运行应用程序的用户可以直接访问数据库,这意味着程序需要提前知道login凭据。 我上面提到的解决scheme不适合这种情况。 您可以将数据库login凭据存储在首选项文件中,但是用户将能够读取该文件,因为他们将是所有者。 事实上,确实没有办法以安全的方式使用这种情况。
正确的案例:使用多层架构
正确的做法是在数据库服务器和客户端应用程序之间build立一个中间层,用于对个人用户进行身份validation,并允许执行一组有限的操作。 每个用户将拥有自己的login凭证,但不能用于数据库服务器。 凭证将允许访问中间层(业务逻辑层),并且对于每个用户都是不同的。
每个用户都有他们自己的用户名和密码,这些用户名和密码可以存储在本地的偏好文件中,没有任何安全风险 这被称为三层体系结构 (层是数据库服务器,业务逻辑服务器和客户端应用程序)。 这是更复杂的,但它确实是做这种事情的最安全的方法。
操作的基本顺序是:
- 客户端使用用户的个人用户名/密码对业务逻辑层进行authentication。 用户名和密码对于用户是已知的,并且不以任何方式与数据库login凭证相关。
- 如果身份validation成功,则客户端向业务逻辑层请求数据库中的某些信息。 例如,产品清单。 请注意,客户端的请求不是SQL查询; 这是一个远程过程调用,如
getInventoryList
。 - 业务逻辑层连接到数据库并检索请求的信息。 业务逻辑层负责基于用户的请求形成安全的SQL查询。 应对SQL查询的任何参数进行消毒,以防止SQL注入攻击。
- 业务逻辑层将清单列表发送回客户端应用程序。
- 客户端将清单列表显示给用户。
请注意,在整个过程中, 客户端应用程序不会直接连接到数据库 。 业务逻辑层接收来自已authentication用户的请求,处理客户机对清单列表的请求,然后才执行SQL查询。
将密码放入应用程序将读取的文件中。 切勿将密码embedded到源文件中。 期。
Ruby有一个叫做DBI :: DBRC的鲜为人知的模块用于这种用法。 我毫不怀疑,Java有一个相当的。 无论如何,写一个不难。
你正在写一个Web应用程序? 如果是这样,请使用JNDI将其configuration到应用程序的外部。 这里有一个概述:
JNDI为应用程序通过networking提供了一种统一的方式来查找和访问远程服务。 远程服务可以是任何企业服务,包括消息传递服务或特定于应用程序的服务,但是当然,JDBC应用程序主要对数据库服务感兴趣。 一旦DataSource对象被创build并注册了一个JNDI命名服务,应用程序就可以使用JNDI API来访问该DataSource对象,然后可以使用它来连接它所表示的数据源。
此问题显示如何将密码和其他数据存储在encryption文件中: Java 256位AES基于密码的encryption
MD5是一种散列algorithm,不是一种encryptionalgorithm,总之你不能回头看看哈希,你只能比较。 在存储用户authentication信息时,最好使用它,而不要使用db用户名和密码。 数据库的用户名和密码应该被encryption并保存在一个configuration文件,至less做。
不pipe你做什么,敏感信息都会存储在某个文件的某个地方。 你的目标是使尽可能难以获得。 您可以实现多less取决于您的项目,您公司的钱包的需求和厚度。
最好的方法是不要在任何地方存储任何密码。 这是通过使用散列函数来生成和存储密码散列来实现的:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
散列algorithm是单向函数。 他们将任何数量的数据转换成不可逆转的固定长度的“指纹”。 它们也具有这样的性质:如果input改变了一点,结果散列就完全不同了(参见上面的例子)。 这对于保护密码是非常好的,因为我们希望将密码保存在一个可以保护密码的forms中,即使密码文件本身已被泄露,但是同时我们需要能够validation用户的密码是否正确。
无关的注意事项:在互联网的旧时代,当您点击“忘记我的密码”链接,网站会通过电子邮件发送您的纯文本密码。 他们可能将这些数据存储在某个数据库中。 当黑客获得访问他们的数据库,他们将获得所有的密码访问。 由于许多用户在多个网站使用相同的密码,这是一个巨大的安全问题。 幸运的是,现在这不是常见的做法。
现在问题是:存储密码的最佳方式是什么? 我认为这个(authentication和用户pipe理服务stormpath的)解决scheme是一个非常非常理想的解决scheme:
- 您的用户input凭据,并对密码散列进行validation
- 生成和存储密码哈希,而不是密码
- 哈希执行多次
- 哈希是使用随机生成的盐生成的
- 哈希用私钥encryption
- 私钥存储在与哈希值不同的地方
- 私钥以基于时间的方式更新
- encryption散列分成块
- 这些块存储在物理上分开的位置
显然你不是谷歌或银行,所以这是一个矫枉过正的解决scheme。 但是接下来会出现这样的问题:您的项目需要多less安全性,多less时间和金钱?
对于许多应用程序,尽pipe不推荐,但在代码中存储硬编码密码可能是一个足够好的解决scheme。 但是,通过从上面的列表中轻松添加几个额外的安全步骤,您可以使您的应用程序更安全。
例如,让我们假设第1步不是您的项目可接受的解决scheme。 您不希望用户每次都input密码,或者甚至不希望/不需要用户知道密码。 你仍然有敏感的信息,你想保护这个。 你有一个简单的应用程序,没有服务器来存储您的文件或这太麻烦您的项目。 您的应用程序运行在无法安全存储文件的环境中。 这是最坏的情况之一,但仍然有一些额外的安全措施,你可以有更安全的解决scheme。 例如,您可以将敏感信息存储在文件中,并且可以encryption文件。 您可以在代码中硬编码encryption专用密钥。 你可以混淆代码,所以你让别人更难以破解它。 有很多这样的库存在,请参阅此链接 。 (我想再次提醒您,这不是100%安全的,一个具有正确的知识和工具的聪明的黑客可以破解这个,但根据您的要求和需求,这可能是一个很好的解决scheme)。