Подтвердить что ты не робот

Защищенный метод для хранения/получения секретного ключа PGP и кодовой фразы?

У меня есть веб-приложение, которое должно хранить информацию для входа в сервер. Я использую 2048-битный открытый ключ PGP для шифрования вставленных паролей (см. insertServerDef) и закрытый ключ с парольной фразой для расшифровки паролей (см. getServerDef).

Как я понимаю, самым слабым звеном в этой цепочке является обработка секретного ключа и кодовой фразы. Как вы можете видеть из моего кода ниже, я просто использую file_get_contents для извлечения ключа и кодовой фразы из файлов, расположенных в текущем веб-каталоге, - нехорошо.

Мой вопрос: что такое хороший метод безопасного получения секретного ключа и кодовой фразы для использования в расшифровке информации для входа в систему? Может быть, я должен хранить/извлекать закрытый ключ через аутентифицированный удаленный файловый сервер?

Я искал лучшие практики, но не смог найти много.

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

}
4b9b3361

Ответ 1

(Примечание: я не специалист по безопасности. У меня есть интерес к этой области, но это. Помните об этом.)

Если возможно, не храните пароли вообще

Это зависит от ваших потребностей. Лучший вариант - не использовать двустороннее шифрование; если вы можете сохранить только соленый и односторонний хэшированный дайджест паролей, который идеально подходит. Вы все еще можете проверить их, чтобы убедиться, что они соответствуют предоставленному паролю от пользователя, но вы никогда его не храните.

Еще лучше, если ваши клиенты используют какой-то разумный протокол (т.е. не HTTP, как обычно реализуемый), вы можете использовать механизм проверки запроса-ответа, что означает, что ваше приложение никогда не будет когда-либо нужно видеть пароль пользователя, даже когда они аутентифицируются. К сожалению, это редко возможно в общедоступной сети, которая имеет безопасность, которая поставила бы 80 программистов на позор.

Если вы должны сохранить пароль, выделите ключи из приложения

Если вы должны иметь возможность расшифровывать пароли, в идеале вы не должны иметь все детали, чтобы сделать это в одном месте и, конечно, не одно доступное для копирования место.

По этой причине я лично предпочел бы не использовать PgCrypto (как вы это делаете) для этой цели, потому что он заставляет вас раскрыть закрытый ключ и (если он есть) кодовую фразу на сервере, где он может быть экспонируются в файлах журнала PostgreSQL или иным образом могут быть обнюханы. Я бы хотел сделать свою криптовую клиентскую сторону, где я мог бы использовать PKCS # 11, ключевой агент или другие инструменты, которые позволяли мне расшифровать данные, не имея при этом моего кода доступа к ключу.

Проблема безопасного хранения ключей является частью того, что было предложено PKCS # 11. Он предоставляет общий интерфейс для приложений и криптопровайдеров, чтобы говорить со всем, что может обеспечить определенные услуги по подписке и расшифровке, даже не раскрывая его ключ. Обычное, но не только использование аппаратных криптоподобных смарт-карт и аппаратных крипто модулей. Такому устройству может быть предложено подписать или дешифровать переданные им данные и сделать это, не раскрывая ключ. Если возможно, подумайте об использовании смарт-карты или HSM. Насколько я знаю, PgCrypto не может использовать PKCS # 11 или другие HSM/смарт-карты.

Если вы не можете этого сделать, вы все равно можете использовать агент управления ключами, где вы загружаете свой ключ в программу управления ключами вручную, когда сервер загружается, а программа управления ключами предоставляет PKCS # 11 (или некоторые другой) интерфейс для подписания и дешифрования через сокет. Таким образом, ваше веб-приложение никогда не должно знать ключ вообще. gpg-agent может претендовать на эту цель. Опять же, насколько я знаю, PgCrypto не может использовать агент управления ключами, хотя это будет отличная возможность добавить.

Даже небольшое улучшение может помочь. Лучше всего, если ключевая фраза для вашего ключа не будет сохранена на диске, поэтому вам может потребоваться ввести ее при запуске приложения, чтобы ключ был расшифрован. Вы все еще сохраняете дешифрованный ключ в памяти, но все детали для его расшифровки больше не находятся на диске и легко доступны. Для злоумышленника намного сложнее украсть дешифрованный ключ из памяти, чем захватить "password.txt" с диска.

То, что вы выбираете, зависит от деталей ваших потребностей в безопасности и данных, с которыми вы работаете. В вашем положении я бы просто не сохранил пароли, если это вообще возможно, и если бы мне пришлось использовать аппаратное устройство, совместимое с PKCS # 11.

Ответ 2

Я считаю, что ответа не может быть, если вы не описали сценарий угрозы, которого вы хотите избежать.

Позвольте мне перефразировать вашу ситуацию: у вас должен быть простой текстовый пароль для доступа к удаленным системам через SSH. Цель состоит в том, чтобы защитить этот пароль, но при необходимости он доступен.

Невозможно защитить пароль и использовать его в форме обычного текста. Всегда есть способ расшифровать его, и для этого нужен как механизм, так и секретный ключ.

Вы можете попробовать немного повторить это, например, снова защитить этот секрет, но в конце вам нужно будет сохранить окончательный текстовый пароль в переменной и передать его в схему аутентификации.

Каков сценарий угрозы, который вы хотите избежать?

  • кто-то крадет дамп вашей базы данных и не должен знать сохраненные пароли
  • кто-то ломается на ваш сервер и читает как базу данных, так и файл с секретной кодовой фразой
  • кто-то ломается на ваш сервер, изменяет ваш script и перехватывает в том месте, где используется расшифрованный текстовый пароль

Видите ли, всегда есть способ причинить вред. Наибольший вред может быть нанесен, если вы регулярно не проверяете неправильную деятельность в ваших системах. Как контролировать все файлы журналов для атак. Вероятно, отправьте журналы на другой сервер syslog, чтобы злоумышленник не мог их изменить, если они находятся на одном сервере. Если вы сделаете все возможное, чтобы предотвратить проникновение злоумышленников в вашу систему, тогда необходимо безопасно хранить секретную кодовую фразу.

Может быть, идея хранить кодовую фразу в ОЗУ, например, на RAM-диске или внутри выделенной памяти. Таким образом, если сервер украден, он, скорее всего, будет отключен и забудет парольную фразу. Но после перезагрузки у вас должен быть способ восстановить кодовую фразу из пульта ДУ для продолжения работы. Но опять же: если вы не можете обнаружить, что атакующий находится в вашей системе, это бессмысленно, является ли кодовая фраза внутри ОЗУ или на магнитном диске - ее можно прочитать.

Интересно, почему вы имеете дело с паролями в первую очередь. Если я использую SSH, я всегда пытаюсь использовать SSH-ключи для криптографической аутентификации. Это более безопасно на целевом сервере, потому что одна учетная запись (например, root) может иметь несколько ключей SSH, а если одна из них хранится на вашем сервере, она может быть удалена без вмешательства в другие ключи. Да, эти ключи SSH также могут быть защищены паролем.

Ответ 3

Я могу делать что-то похожее на вас. В настоящее время я хочу защитить личную информацию в локальной базе данных веб-сервера, поэтому я шифрую ее открытым ключом (хранящимся на самом веб-сервере) и дешифруя его с помощью закрытого ключа, хранящегося в куки файле с коротким сроком службы (30 минут для меня).

По SSL-соединению это не позволит ключу попасть в неправильные руки и не сохраняет его на сервере. В идеале я должен дважды проверить, что PHP не кэширует значения cookie на сервере, но даже если это так, этот уровень безопасности по-прежнему представляет собой более серьезное препятствие для злоумышленников, чем просто кражу базы данных открытого текста.

Будет ли это хорошим подходом для вас, зависит от того, нужно ли вашему приложению получать доступ к учетным данным сервера, даже если пользователи не вошли в систему через Интернет. В моем случае дешифрование требуется только через веб-приложение, поэтому файл cookie достаточно. Однако, если вам требуется автоматическое использование, вам нужно будет сохранить закрытый ключ на сервере.