Ell*_* B. 12 php security postgresql pdo pgp
我有一个需要存储服务器登录信息的Web应用程序.我正在使用2048位PGP公钥来加密插入的密码(请参阅参考资料insertServerDef)和带密码的私钥来解密密码(请参阅参考资料getServerDef).
据我所知,这个链中最薄弱的环节是处理私钥和密码.从下面的代码中我可以看到,我只是file_get_contents用来从当前web目录中的文件中检索密钥和密码 - 不好.
我的问题是:安全检索私钥和密码用于解密登录信息的好方法是什么?也许我应该通过经过身份验证的远程文件服务器存储/检索私钥?
我搜索过最佳实践,但却找不到多少.
class DB {
protected $_config;
protected $_iUserId;
protected $_iServerId;
protected $_dbConn;
protected $_sPubKey;
protected $_sPrivKey;
public function __construct($iUserId, $iServerId) {
//bring the global config array into local scope
global $config;
$this->_config = $config;
$this->_iUserId = $iUserId;
$this->_iServerId = $iServerId;
$this->_sPubKey = file_get_contents("public_key");
$this->_sPrivKey = file_get_contents("private_key");
$this->_sPrivKeyPass = trim(file_get_contents("private_key_pass"));
}
//connect to the database
public function connect() {
try {
$this->_dbConn = new PDO("pgsql:host=".$this->_config['db_host']." dbname=".$this->_config['db_name'],$this->_config['db_username'],$this->_config['db_password']);
echo "PDO connection object created";
} catch(PDOException $e) {
echo $e->getMessage();
}
}
public function insertServerDef($sHost, $iPort, $sUser, $sPass) {
//testing
$iUserId = 1;
$oStmt = $this->_dbConn->prepare("INSERT INTO upze_server_def (server_id, host_address, ssh_port, username, pass, user_id) VALUES (DEFAULT, :host_address, :ssh_port, :username, pgp_pub_encrypt(:pass,dearmor(:pub_key)), :user_id)");
$oStmt->bindParam(':host_address',$sHost);
$oStmt->bindParam(':ssh_port',$iPort);
$oStmt->bindParam(':username',$sUser);
$oStmt->bindParam(':pass',$sPass);
$oStmt->bindParam(':pub_key',$this->_sPubKey);
$oStmt->bindParam(':user_id',$iUserId);
$oStmt->execute();
}
public function getServerDef($iServerId) {
$oStmt = $this->_dbConn->prepare(" SELECT server_id, pgp_pub_decrypt(pass,dearmor(:priv_key),:priv_key_pass) As decryptpass
FROM upze_server_def usd
WHERE usd.server_id = :server_id
");
$oStmt->bindParam(':server_id', $iServerId);
$oStmt->bindParam(':priv_key', $this->_sPrivKey);
$oStmt->bindParam(':priv_key_pass', $this->_sPrivKeyPass);
$oStmt->execute();
while($row = $oStmt->fetch()) {
echo "<pre>".print_r($row)."</pre>";
}
}
//close any existing db connection
public function close() {
$this->_dbConn = null;
}
//close any existing db connections on unload
public function __destruct() {
$this->_dbConn = null;
}
}
Run Code Online (Sandbox Code Playgroud)
(注意:我不是安全专家.我对该领域感兴趣,但就是这样.记住这一点.)
这很大程度上取决于您的需求.最好的选择是根本不使用双向加密; 如果你只能存储理想的盐渍和单向散列密码摘要.您仍然可以测试它们以查看它们是否与用户提供的密码匹配,但您从不存储它.
更妙的是,如果您的客户端使用一些理智的协议(即:不为http普遍实施的),你可以使用一个挑战-响应验证机制从未意味着你的应用程序不断需要看到用户的密码,进行身份验证即使是在他们.遗憾的是,在公共网站上很少有这种情况,因为公共网络的安全性让80位程序员感到羞耻.
如果你必须能够解密的密码,最好你不应该有所有细节在一个地方这样做,肯定不是一个拷贝,但交通方便的地方.
出于这个原因,我个人不希望为此目的使用PgCrypto(正如你所做的那样),因为它迫使你向服务器显示私钥和(如果有的话)密码,它可以在PostgreSQL中暴露出来.日志文件或以其他方式可能被嗅探.我想要我的加密客户端,我可以使用PKCS#11,密钥代理或其他工具,让我解密数据,而无需我的代码能够访问密钥.
安全密钥存储的问题是PKCS#11发明的一部分.它为应用程序和加密提供程序提供了一个通用接口,可以与任何可以提供某些签名和解密服务的内容进行通信,而无需泄露其密钥.通常但不仅仅是使用基于硬件的加密,如智能卡和硬件加密模块.可以告诉这些设备签署或解密传递给他们的数据,并且可以在不泄露密钥的情况下这样做.如果可能,请考虑使用智能卡或HSM.据我所知,PgCrypto不能使用PKCS#11或其他HSM /智能卡.
如果您不能这样做,您仍然可以使用密钥管理代理,在服务器引导时手动将密钥加载到密钥管理程序中,密钥管理程序提供PKCS#11(或其他)接口用于通过套接字进行签名和解密.这样你的网络应用程序根本不需要知道密钥.gpg-agent可能有资格达到这个目的.同样,据我所知,PgCrypto无法使用密钥管理代理,尽管它是一个很棒的功能.
即使是小改进也可以提供帮助.最好是密钥的密码不存储在磁盘上,因此您可能需要在应用程序启动时输入密钥才能解密密钥.您仍然将解密的密钥存储在内存中,但解密它的所有细节都不再存在于磁盘上且易于获取.攻击者从内存中窃取解密密钥比从磁盘中获取"password.txt"要困难得多.
您选择做什么在很大程度上取决于您的安全需求和您正在使用的数据的详细信息.在你的位置,如果可能的话,我不会存储密码,如果我不得不想要使用与PKCS#11兼容的硬件设备.
| 归档时间: |
|
| 查看次数: |
4887 次 |
| 最近记录: |