问题 为什么不用DriverManager.getConnection(String url,String user,char []密码)?


我们知道优先选择char []而不是java.lang.String来存储密码。这是出于以下两个原因(正如我所读到的):

  1. char []是可变的,因此我们可以在使用后清除密码。
  2. 字符串文字转到不会将垃圾收集为其他对象的池,因此可能会出现在内存转储中。

但是java.sql.DriverManager没有符合上述最佳实践的getConnection(),因为它的password参数是String。

DriverManager.getConnection(String url,String user,String password)

我认为API应该有一个带有以下签名的重载方法:

DriverManager.getConnection(String url,String user, 炭[] 密码)

你怎么看待这件事?你有没有看到任何替代方法来克服这种退缩?

很想听听你的想法。


1473
2018-02-15 14:28


起源



答案:


文字 进入一个池,但我不希望密码是文字(在程序中硬编码)。我希望它来自配置或类似。因此,它不会是文字和  收集垃圾(如果所有引用都被分箱)。


4
2018-02-15 14:38





你提出了一个很好的观点,大多数人都回答错过了。最糟糕的情况是操作系统将“临时”密码换掉,明文时请注意。在此之后,这个交换文件很容易被读取,如果攻击者有大约1500美元的设备,在磁盘上甚至可以被零覆盖...

您可以做的最好是connect,password = null,然后显式调用gc()。如果幸运的话,这将清除驱动程序实现使用的字符串。

无论如何......

  • 你问的问题目前是不可能的,但会很好。
  • 甚至char []也可以在某些条件下存活(例如交换)。
  • 您的密码将在前往数据库的路上多次复制,因此char []仅解决问题的一部分。

现实情况是,除非平台是专门为安全而设计的,否则所有方法都只是拖延战术。做,你能做什么,但如果确定的人可以访问你的机器,char []将获得最多1小时。


3
2018-04-05 20:45





除非您可以询问API的设计者,否则只能推测。

我猜测是这样的:

使用的主要API char[] 代替 String 对于我所知道的密码 JPasswordField。它这样做是为了允许程序在使用值后用其他值覆盖用户输入的密码(这是不可能的 String,这将留在记忆中 至少 直到它被垃圾收集)。

在我所知道的大多数应用程序中,用于连接数据库的密码通常不是用户输入的,而是来自某种配置/目录/ ...

无论它来自何处:应用程序能够在不再知道后重新构建它。这是用户输入的密码和以编程方式获取的密码之间的巨大差异。

由于密码通常可以通过更简单的方式获取,而不是搜索程序使用的所有内存,因此修复此攻击向量不是一个高优先级

</speculation>


2
2018-02-15 14:43





你的理由#2是我见过的最常用的字符串使用char []。但是,一般来说,我认为如果你假设某人可以通过调试器或其他方式访问你的程序状态,那么他们就没有理由不能查看char []的内容。


2
2018-02-15 14:44





使用char []数组的参数最适用于用户键入密码的位置,并且您希望最小化该密码的暴露。

JDBC连接几乎从不这样。密码存储在某些配置文件中,可能是模糊处理的,并且是泄漏源,而不是读取内存的可能性。

无论如何,JDBC标准允许在属性对象甚至URL中传递密码,所以我认为有一个 char[] 密码参数会给你一种错误的安全感。

如果你有一个真正的用例,需要尽可能快地从内存中删除密码以使其无法恢复,并且在真正的JDBC应用程序的上下文中有其他意义,我很乐意听到它。我可以想象这样的事情可能存在,但我想不出一个使用a的场景 char[] 真的让事情更安全。


2
2018-02-15 14:51



关于“JDBC连接几乎从不那样”的有趣注释。我来寻找这个话题,因为在我们的例子中 是 像那样。用户正在输入密码,我们试图尽可能保证密码,然后某些API - 即JDBC和URL,以这种方式搞砸了,然后我们又回到没有通过切换到char来改进任何东西[]。 :( - Trejkaz


答案:


文字 进入一个池,但我不希望密码是文字(在程序中硬编码)。我希望它来自配置或类似。因此,它不会是文字和  收集垃圾(如果所有引用都被分箱)。


4
2018-02-15 14:38





你提出了一个很好的观点,大多数人都回答错过了。最糟糕的情况是操作系统将“临时”密码换掉,明文时请注意。在此之后,这个交换文件很容易被读取,如果攻击者有大约1500美元的设备,在磁盘上甚至可以被零覆盖...

您可以做的最好是connect,password = null,然后显式调用gc()。如果幸运的话,这将清除驱动程序实现使用的字符串。

无论如何......

  • 你问的问题目前是不可能的,但会很好。
  • 甚至char []也可以在某些条件下存活(例如交换)。
  • 您的密码将在前往数据库的路上多次复制,因此char []仅解决问题的一部分。

现实情况是,除非平台是专门为安全而设计的,否则所有方法都只是拖延战术。做,你能做什么,但如果确定的人可以访问你的机器,char []将获得最多1小时。


3
2018-04-05 20:45





除非您可以询问API的设计者,否则只能推测。

我猜测是这样的:

使用的主要API char[] 代替 String 对于我所知道的密码 JPasswordField。它这样做是为了允许程序在使用值后用其他值覆盖用户输入的密码(这是不可能的 String,这将留在记忆中 至少 直到它被垃圾收集)。

在我所知道的大多数应用程序中,用于连接数据库的密码通常不是用户输入的,而是来自某种配置/目录/ ...

无论它来自何处:应用程序能够在不再知道后重新构建它。这是用户输入的密码和以编程方式获取的密码之间的巨大差异。

由于密码通常可以通过更简单的方式获取,而不是搜索程序使用的所有内存,因此修复此攻击向量不是一个高优先级

</speculation>


2
2018-02-15 14:43





你的理由#2是我见过的最常用的字符串使用char []。但是,一般来说,我认为如果你假设某人可以通过调试器或其他方式访问你的程序状态,那么他们就没有理由不能查看char []的内容。


2
2018-02-15 14:44





使用char []数组的参数最适用于用户键入密码的位置,并且您希望最小化该密码的暴露。

JDBC连接几乎从不这样。密码存储在某些配置文件中,可能是模糊处理的,并且是泄漏源,而不是读取内存的可能性。

无论如何,JDBC标准允许在属性对象甚至URL中传递密码,所以我认为有一个 char[] 密码参数会给你一种错误的安全感。

如果你有一个真正的用例,需要尽可能快地从内存中删除密码以使其无法恢复,并且在真正的JDBC应用程序的上下文中有其他意义,我很乐意听到它。我可以想象这样的事情可能存在,但我想不出一个使用a的场景 char[] 真的让事情更安全。


2
2018-02-15 14:51



关于“JDBC连接几乎从不那样”的有趣注释。我来寻找这个话题,因为在我们的例子中 是 像那样。用户正在输入密码,我们试图尽可能保证密码,然后某些API - 即JDBC和URL,以这种方式搞砸了,然后我们又回到没有通过切换到char来改进任何东西[]。 :( - Trejkaz


您的第1点在某种程度上是有效的,但关于字符串结束在未收集的字符串池中的第2点仅适用于静态文字字符串(直接出现在代码中的字符串)。如果您将密码直接存储在您的代码中,我建议首先担心这些密码,因为在类文件中找到密码要比在正在运行的VM中更容易。

因此,如果您认为必须将密码存储在char []中,则在调用getConnection()之前仍可以从中创建String对象。如果驱动程序实现没有在内部存储字符串对象,则它将很快无法访问,因此可以非常快速地收集。当时仍然只能读取它的唯一机会是直接检查JVM的内存。所以你是对的,使用char []会更安全,但不是很多,因为无论如何密码都必须在内存中。

即使用任何类型的API获取密码的一种非常简单的方法是注入伪造的SQL驱动程序并直接在connect方法中获取密码。谁能够检查JVM内存以找到其中尚未覆盖的密码字符串,也可以注入修改后的驱动程序jar。


1
2018-02-15 14:54



关于JDBC的可插拔特性如何使用自己的驱动程序替换驱动程序非常容易。 - Yishai