我不想在应用程序配置文件中放入未加密的密码。
这个问题:在application.conf中加密数据库密码有一个很好的解决方案,但它只适用于Play 1。
有人知道适用于Play 2.0的解决方案吗?我在Play 2.0.2的Scala版本中使用anorm。
所有的努力都是毫无意义的。当我们将散列密码放入数据库时,是因为人类可以将密码保留在大脑中,而他们的大脑是不可读的。它被称为非对称加密。
您所说的事情只有在对称加密的情况下才可能发生:程序在运行时拥有密钥,并使用该密钥解密数据库密码。但是,存储用密钥加密的数据库密码,并公开该密钥有什么意义呢?(对于java源代码和编译后的类都是如此)。一条链条只有最薄弱的环节才有力量。
当一台机器必须连接到数据库时,它需要一个密码:我们将此密码以纯文本形式存储,因为程序必须按原样使用,并且不需要人工输入。为了加强安全性,我们所能做的就是限制对该纯文本文件的访问,最终用只存储在管理员脑海中的密码来保护它(顺便说一句,管理员更有可能将其所有密码保存在数据库中,可能是用主密码)。注意,如果你使用上面提到的Play插件,情况不会改变。
我脑海中唯一想到的是一个Play应用程序,它只在管理员输入数据库密码时连接到数据库(但实际上这只是一个思考练习)
我知道时间有点晚了,但没有关于这个问题的新讨论。我想分享实际的解决方案(Play v.2.5.X),正如文档中所建议的,现在可以覆盖GuiceApplicationLoader
来配置GuiceApplicationBuilder
以某种方式处理初始配置。
在新的类别modules/ApplicationLoaderConfig.scala
:中
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import javax.xml.bind.DatatypeConverter
import play.api.inject.guice._
import play.api.{ApplicationLoader, Configuration}
class ApplicationLoaderConfig extends GuiceApplicationLoader() {
override def builder(context: ApplicationLoader.Context): GuiceApplicationBuilder = {
// Decrypt secrets
val decryptedConfig = context.initialConfiguration ++
Configuration("config.to.descrypt.1" -> decryptDES(context.initialConfiguration.getString("config.to.descrypt.1").get)) ++
Configuration("config.to.descrypt.2" -> decryptDES(context.initialConfiguration.getString("config.to.descrypt.2").get))
initialBuilder
.in(context.environment)
.loadConfig(decryptedConfig)
.overrides(overrides(context): _*)
}
private def decryptDES(secret: String): String = {
val key = "12345678"
val skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "DES")
val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, skeySpec)
new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(secret)))
}
}
同时添加到application.config
:
play.application.loader = "modules.ApplicationLoaderConfig"
感谢与Raffaele的讨论,并根据我自己对代码的调查,Play 2.0似乎不允许您加密DB密码。
如果我错过了什么,请告诉我。
EDIT:可以通过以下方式使用自定义数据库驱动程序来解决此问题:
// Just redirect everything to the delegate
class DelegatingDriver(delegate: Driver) extends Driver
{
def connect(url: String, info: Properties) = delegate.connect(url, info)
def acceptsURL(url: String) = delegate.acceptsURL(url)
def getPropertyInfo(url: String, info: Properties) = delegate.getPropertyInfo(url, info)
def getMajorVersion = delegate.getMajorVersion
def getMinorVersion = delegate.getMinorVersion
def jdbcCompliant() = delegate.jdbcCompliant()
}
// Replace password in properties with the decrypted one
class MyDecryptingDriver extends DelegatingDriver(Class.forName("<my.original.Driver>").newInstance().asInstanceOf[Driver])
{
override def connect(url: String, info: Properties)= {
// copy Properties
val overriddenProperties= clone(info)
// override password property with the decrypted value
Option(info.getProperty("password")).foreach(value => overriddenProperties.setProperty("password", decryptPassword(value)))
super.connect(url, overriddenProperties)
}
def clone(orig: Properties)= {
val result= new Properties()
orig.propertyNames().map(_.asInstanceOf[String]).foreach(pName => result.setProperty(pName, orig.getProperty(pName)))
result
}
def decryptPassword(encrypted: String)= ...
}
然后用my.com.MyDecrypting驱动程序替换application.conf/db.driver。不完美,但适用于我…