用于存储/检索PGP私钥和密码的安全方法? [英] Secure method for storing/retrieving a PGP private key and passphrase?

查看:72
本文介绍了用于存储/检索PGP私钥和密码的安全方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Web应用程序,需要存储服务器登录信息.我正在使用2048位PGP公钥来加密插入的密码(请参见insertServerDef),并使用带有密码短语的私钥来对密码进行解密(请参见getServerDef).

I have a web application that needs to store server login information. I'm using a 2048bit PGP public key to encrypt inserted passwords (see the insertServerDef) and a private key with a passphrase to decrypt the passwords (see getServerDef).

据我了解,该链中最薄弱的环节是私钥和密码短语的处理.从下面的代码中可以看到,我只是使用file_get_contents从当前Web目录中的文件中检索密钥和密码短语-不好.

As I understand things, the weakest link in this chain is the handling of the private key and passphrase. As you can see from my code below, I'm just using file_get_contents to retrieve the key and passphrase from files located in the current web directory--not good.

我的问题是:安全地检索用于解密登录信息的私钥和密码的一种好方法是什么?也许我应该通过经过身份验证的远程文件服务器存储/检索私钥?

My question is: what is a good method for securely retrieving the private key and passphrase for use in decrypting login info? Maybe I should store/retrieve the private key via an authenticated remote file server?

我一直在寻找最佳实践,但是却找不到很多.

I've searched for best practices, but haven't been able to find much.

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;
    }

}

推荐答案

(注意:我不是安全专家.我对该领域感兴趣,但是仅此而已.请记住这一点.)

(Note: I'm no security expert. I have an interest in the area, but that's it. Keep that in mind.)

这在很大程度上取决于您的需求.最好的选择是根本不使用双向加密.如果您只能存储盐腌

It depends a lot on what your needs are. The best option of all is not to use two-way encryption at all; if you can store only salted and one-way-hashed password digests that's ideal. You can still test them to see if they match a supplied password from the user, but you never store it.

更好的是,如果您的客户端使用一些理智的协议(即:不是通常实现的HTTP),则可以使用

Better still, if your clients use some sane protocol (ie: not HTTP as commonly implemented) you can use a challenge-response authentication mechanism that means your app never ever needs to see the user's password, not even when authenticating them. Sadly this is rarely possible on the public web, which has security that'd put 80's programmers to shame.

如果您必须能够解密密码,理想情况下,您不应将所有详细信息都放在一个地方,当然也不应该在一个可复制且易于访问的地方.

If you must be able to decrypt the passwords, ideally you shouldn't have all the details to do so in one place, and certainly not one copyable, easily accessible place.

由于这个原因,我个人不希望出于此目的使用PgCrypto(因为您正在这样做),因为它会强制您显示私钥,并且(如果有)将密码短语发送到服务器(可能在其中)暴露在PostgreSQL的日志文件中或可能被嗅探到.我想做我的加密客户端,在这里我可以使用PKCS#11,密钥代理或其他工具,这些工具可以让我解密数据而无需使我的代码能够访问密钥.

For that reason I'd personally prefer not to use PgCrypto (as you're doing) for this purpose because it forces you to reveal the private key and (if it has one) passphrase to the server, where it could be exposed in PostgreSQL's log files or otherwise potentially sniffed. I'd want to do my crypto client-side, where I could use PKCS#11, a key agent, or other tools that let me decrypt the data without ever having my code able to access the key.

安全密钥存储的问题是发明 PKCS#11 的一部分.它为应用程序和加密提供者提供了一个通用接口,可以与任何可以提供某些签名和解密服务的交易进行对话,而不会泄露其密钥.通常(但不仅限于)与基于硬件的加密算法一起使用,例如智能卡和硬件加密模块.可以告知此类设备对传递给它们的数据进行签名或解密,并且无需公开密钥就可以这样做.如果可能,请考虑使用智能卡或HSM.据我所知,PgCrypto无法使用PKCS#11或其他HSM/智能卡.

The problem of secure key storage is part of what PKCS#11 was invented for. It provides a generic interface for applications and crypto providers to talk to anything that can provide certain signing and decryption services without ever revealing its key. The usual, but not only, use is with hardware based crypto like smart cards and hardware crypto modules. Such devices can be told to sign or decrypt data passed to them, and can do so without ever revealing the key. If possible, consider using a smartcard or HSM. As far as I know PgCrypto cannot use PKCS#11 or other HSMs/smartcards.

如果无法执行此操作,则仍可以使用密钥管理代理,在该代理中,当服务器启动时,您将密钥手动加载到密钥管理程序中,并且密钥管理程序提供了PKCS#11(或某些).其他)接口,用于通过套接字进行签名和解密.这样,您的Web应用程序根本不需要知道密钥. gpg-agent可能符合此目的.再次,据我所知,PgCrypto无法使用密钥管理代理,尽管这将是一个很棒的功能.

If you can't do that, you can still probably use a key management agent, where you load your key into a key management program manually when the server boots, and the key management program provides a PKCS#11 (or some other) interface for signing and decryption via a socket. That way your web app never needs to know the key at all. gpg-agent may qualify for this purpose. Again, as far as I know PgCrypto cannot use a key management agent, though it'd be a great feature to add.

即使有一点点改进也可以提供帮助.最好将密钥的密码短语未存储在磁盘上,因此您可能需要在启动应用程序时输入密码,以便可以解密密钥.您仍将解密后的密钥存储在内存中,但是解密它的所有详细信息都不再存在于磁盘上,并且很容易获得.对于攻击者来说,从内存中窃取解密的密钥比从磁盘上获取"password.txt"要困难得多.

Even a small improvement can help. It's best if the passphrase for your key isn't stored on disk, so you might require it to be entered when the app is started up so the key can be decrypted. You're still storing the decrypted key in memory, but all the details to decrypt it are no longer on disk and easy to get at. It's much harder for an attacker to steal the decrypted key from memory than to grab a "password.txt" from disk.

您选择执行的操作在很大程度上取决于安全需求和正在使用的数据的详细信息.在您的位置上,如果可能的话,我只会存储密码,如果必须的话,我想使用兼容PKCS#11的硬件设备.

What you choose to do depends a lot on the details of your security needs and the data you're working with. In your position I'd just not store the passwords if at all possible, and if I had to I'd want to use a PKCS#11-compatible hardware device.

这篇关于用于存储/检索PGP私钥和密码的安全方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆