用于存储/检索PGP私钥和密码安全的方法?(Secure method for storing/re

2019-06-28 01:29发布

我有一个需要存储服务器登录信息的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;
    }

}

Answer 1:

(注:我不是安全专家我有在该地区的利益,但仅此而已记住这一点。)

如果可能的话,不要将密码存放在所有

这取决于你的需求是什么了很多。 所有的最好的选择是完全不使用双向加密; 如果你只能存储腌制和单向散列密码摘要这是理想的。 您仍然可以进行测试,看看它们是否匹配从用户提供的密码,但你永远保存。

更妙的是,如果您的客户端使用一些理智的协议(即:不为http普遍实施的),你可以使用一个挑战-响应验证机制从未意味着你的应用程序可能需要以看到用户的密码,进行身份验证即使是在他们。 可悲的是,这是几乎不可能的公共网络,它具有的安全性,就会把80年代的程序员耻辱。

如果您必须存储密码,从应用程序隔离键

如果你必须能够解密的密码,最好你不应该有所有细节在一个地方这样做,肯定不是一个拷贝,但交通方便的地方。

出于这个原因,我个人不喜欢使用PgCrypto(如你正在做的),为了这个目的,因为它迫使你透露私钥和(如果有的话)密码到服务器,它可以在PostgreSQL的暴露日志文件或其他潜在的嗅探。 我愿意做我的加密客户端,在那里我可以用PKCS#11,一个关键的代理人,或者让我对数据进行解密时无需我的代码能够访问关键的其他工具。

安全密钥存储的问题是哪一部分的PKCS#11是发明了。 它提供了应用程序和加密提供商去跟任何可以提供一定的签名和加密服务, 而没有揭示其关键的通用接口。 通常的,但不是唯一的,使用的是基于硬件的加密,如智能卡和硬件加密模块。 这种设备可以告诉签名或解密传递给它们的数据,并且可以无需显示关键这么做。 如果可能的话,可以考虑使用智能卡或HSM。 据我所知PgCrypto不能使用PKCS#11或其他硬件安全模块/智能卡。

如果你不能做到这一点,你可以仍然可能使用一个密钥管理代理,在哪儿加载密钥导入密钥管理程序手动服务器启动时,密钥管理方案提供了一个PKCS#11(或其他)接口用于通过插座签名和加密。 这样,你的web应用程序永远不需要知道密钥的。 gpg-agent可能有资格获得这一目的。 此外,据我所知PgCrypto不能使用密钥管理代理,但它会是一个很大的特点来补充。

即使是很小的改进可以提供帮助。 这是最好的,如果你的密钥密码并不存储在磁盘上,因此你可能需要在应用程序启动了,因此密钥可以解密它来输入。 你还是在内存中存储解密密钥,但所有的细节解密它在磁盘上不再易得的。 这是更难攻击者从内存中窃取解密密钥,而不是抓住从磁盘上的“password.txt”。

是什么让你选择做了很多取决于您的安全需要的细节和你正在使用的数据。 在你的位置,我只是不存储密码,如果可能的话,如果我不得不我想使用一个PKCS#11兼容的硬件设备。



Answer 2:

我可能会做类似你的东西。 我现在要保护本地Web服务器数据库中的个人信息,所以我用公开密钥(存储在Web服务器本身)进行加密,并与存储在cookie中有寿命短的私钥解密它(30分钟,我)。

通过SSL连接,这将让钥匙落入坏人之手,它不会将其存储在服务器上。 理想情况下,我应该仔细检查PHP不会在服务器上缓存cookie的值,但即使是这样,这个安全层仍然代表了攻击者不是简单地窃取明文数据库中的更大的障碍。

你要看你的应用程序是否需要访问甚至服务器凭证时,通过网络还没有登录的用户是否这将是一个不错的办法。 在我的情况下,解密仅通过Web应用程序所需要的,所以饼干就足够了。 但是,如果你需要无人值守的使用,您将需要在服务器上存储的私钥。



Answer 3:

我相信,除非你描述你想避免威胁的情况下不可能有答案。

让我改一下你的情况:你需要有通过SSH访问远程系统上的明文密码。 我们的目标是保护这个密码,但在需要的时候有它可用。

实在没有办法,既保护密码,并能够在其纯文本的形式使用。 有总是要来解密的方式,这既需要机制和密钥。

你可以尝试重复了一下这个,再如保护这个秘密,但最终你需要将最终明文密码存储到一个变量,并传递到认证方案。

什么是你想避免威胁的情况?

  • 有人偷了你的数据库的转储,不应该知道存储的密码
  • 有人闯入你的服务器,读取数据库和与秘密口令文件
  • 有人闯入你的服务器,在该点会改变你的脚本和拦截在使用解密的明文密码

你看,总有办法做到的伤害。 如果你没有对违规行为定期检查您的系统上危害性最大可以做到的。 像监视所有日志文件的攻击。 也许日志发送到另一个系统日志服务器,使攻击者无法改变他们,如果他们是在同一台服务器上。 如果你做的一切,你可以阻止攻击者获取到您的系统,那么就需要安全地存储的秘密口令减少。

这可能是对密码存储到RAM,像RAM磁盘或专用的存储器内的想法。 这样一来,如果服务器被盗,它最有可能将是无动力的,而忘记了密码。 但是,你则必须有办法从远程恢复密码在重新启动后继续工作。 但是,再次:如果你不能检测攻击者在你的系统上,这是毫无意义的密码是否是内部RAM或磁盘上 - 它可以被读取。

我不知道为什么你处理摆在首位的密码。 如果我使用SSH,我总是尝试使用SSH密钥进行加密认证。 这是在目标服务器上更安全,因为一个帐号(如根)可以有多个SSH密钥,如果存储在服务器上的一个被攻破,它可以在不与其他键的干扰被删除。 是的,这些SSH密钥可以使用密码来固定,太。



文章来源: Secure method for storing/retrieving a PGP private key and passphrase?