extension - php postgresql
Método seguro para almacenar/recuperar una clave privada de PGP y una frase de contraseña? (3)
(Nota: no soy un experto en seguridad. Tengo un interés en el área, pero eso es todo. Tenga esto en cuenta).
Si es posible, no almacene contraseñas en absoluto
Depende mucho de tus necesidades. La mejor opción de todas es no usar en absoluto el cifrado bidireccional; si puedes almacenar solo resúmenes de contraseñas saladas y de hash unidireccional que es ideal. Todavía puede probarlos para ver si coinciden con una contraseña proporcionada por el usuario, pero nunca la almacena.
Mejor aún, si sus clientes usan algún protocolo razonable (es decir: no HTTP como comúnmente implementado) puede usar un mecanismo de autenticación desafío-respuesta que significa que su aplicación nunca necesita ver la contraseña del usuario, ni siquiera cuando los autentica. Lamentablemente, esto rara vez es posible en la red pública, que tiene una seguridad que avergonzaría a los programadores de los 80.
Si debe almacenar la contraseña, aísle las claves de la aplicación
Si debe poder descifrar las contraseñas, lo ideal es que no tenga todos los detalles para hacerlo en un solo lugar, y ciertamente no es un lugar fácilmente accesible.
Por esa razón, personalmente prefiero no usar PgCrypto (como lo está haciendo) para este propósito porque te obliga a revelar la clave privada y (si tiene una) frase de paso al servidor, donde podría estar expuesta en PostgreSQL. archivos de registro o de otro modo potencialmente olfateado. Me gustaría hacer mi cripto-cliente, donde podría usar PKCS # 11, un agente clave, u otras herramientas que me permitan descifrar los datos sin tener mi código capaz de acceder a la clave.
El problema del almacenamiento seguro de claves es parte de lo que se inventó para PKCS # 11 . Proporciona una interfaz genérica para que las aplicaciones y los proveedores de cifrado hablen con cualquier cosa que pueda proporcionar ciertos servicios de firma y descifrado sin revelar su clave . El uso usual, pero no único, es con las tarjetas inteligentes similares a criptografía basadas en hardware y los módulos criptográficos de hardware. A dichos dispositivos se les puede indicar que firmen o descifren los datos que se les pasan, y pueden hacerlo sin revelar la clave. Si es posible, considere usar una tarjeta inteligente o HSM. Por lo que sé, PgCrypto no puede usar PKCS # 11 u otros HSM / tarjetas inteligentes.
Si no puede hacer eso, probablemente aún pueda usar un agente de administración de claves, donde cargue manualmente su clave en un programa de administración de claves cuando se inicie el servidor, y el programa de administración de claves proporciona una interfaz PKCS # 11 (o alguna otra) para firmar y descifrar a través de un socket. De esta manera, su aplicación web nunca necesita saber la clave en absoluto. gpg-agent
puede calificar para este propósito. De nuevo, hasta donde yo sé, PgCrypto no puede usar un agente de administración de claves, aunque sería una gran característica para agregar.
Incluso una pequeña mejora puede ayudar. Lo mejor es que la frase de contraseña para su clave no esté almacenada en el disco, por lo que puede requerir que se ingrese cuando la aplicación se inicie para que la clave pueda descifrarse. Todavía está almacenando la clave descifrada en la memoria, pero todos los detalles para descifrarla ya no están en el disco y son fáciles de conseguir. Para un atacante es mucho más difícil robar la clave descifrada de la memoria que tomar un "password.txt" del disco.
Lo que elija hacer depende en gran medida de los detalles de sus necesidades de seguridad y de los datos con los que está trabajando. En su posición, simplemente no almacenaría las contraseñas si fuera posible, y si tuviera que hacerlo, querría usar un dispositivo de hardware compatible con PKCS # 11.
Tengo una aplicación web que necesita almacenar información de inicio de sesión del servidor. Estoy usando una clave pública PGP de 2048 bits para cifrar las contraseñas insertadas (vea insertServerDef
) y una clave privada con una frase de contraseña para descifrar las contraseñas (vea getServerDef
).
Según entiendo las cosas, el eslabón más débil de esta cadena es el manejo de la clave privada y la frase de contraseña. Como puede ver en mi código a continuación, solo estoy usando file_get_contents
para recuperar la clave y la frase de contraseña de los archivos ubicados en el directorio web actual, lo que no es bueno.
Mi pregunta es: ¿cuál es un buen método para recuperar de forma segura la clave privada y la frase de contraseña para descifrar la información de inicio de sesión? ¿Tal vez debería almacenar / recuperar la clave privada a través de un servidor de archivos remoto autenticado?
He buscado las mejores prácticas, pero no he podido encontrar mucho.
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;
}
}
Creo que no puede haber una respuesta a menos que describa el escenario de amenaza que desea evitar.
Permítanme reformular su situación: debe tener una contraseña de texto sin formato para acceder a los sistemas remotos a través de SSH. El objetivo es proteger esta contraseña, pero tenerla disponible cuando sea necesario.
Realmente no hay forma de proteger la contraseña y poder usarla en su forma de texto plano. Siempre tiene que haber una forma de descifrarlo, y esto necesita tanto el mecanismo como la clave secreta.
Puede tratar de iterar un poco sobre esto, como proteger este secreto nuevamente, pero al final tendrá que almacenar la contraseña final de texto plano en una variable y pasarla al esquema de autenticación.
¿Cuál es el escenario de amenaza que quieres evitar?
- alguien roba un volcado de su base de datos y no debe saber las contraseñas almacenadas
- alguien irrumpe en su servidor y lee tanto la base de datos como el archivo con la contraseña secreta
- alguien irrumpe en su servidor, altera su secuencia de comandos e intercepta en el punto donde se utiliza la contraseña descifrada de texto plano
Usted ve, siempre hay una manera de hacer daño. La mayoría de los daños se pueden hacer si no revisa regularmente la actividad irregular en sus sistemas. Como supervisar todos los archivos de registro para los ataques. Probablemente envíe los registros a otro servidor syslog para que un atacante no pueda cambiarlos si están en el mismo servidor. Si hace todo lo posible para evitar que los atacantes ingresen a su sistema, la necesidad de almacenar de forma segura la contraseña secreta disminuye.
Puede ser una idea almacenar la frase de contraseña en la RAM, como en un disco RAM o dentro de una memoria dedicada. De esta forma, si el servidor es robado, lo más probable es que no lo tenga y olvide la frase de contraseña. Pero luego debe tener una forma de restablecer la contraseña del control remoto para continuar con la operación después de reiniciar. Pero nuevamente: si no puede detectar que un atacante está en su sistema, no tiene sentido si la frase de contraseña está dentro de la RAM o en el disco magnético, puede leerse.
Me pregunto por qué lidiar con contraseñas en primer lugar. Si uso SSH, siempre trato de usar claves SSH para la autenticación criptográfica. Esto es más seguro en el servidor de destino, porque una cuenta (como root) puede tener varias claves SSH, y si la que está almacenada en su servidor está en peligro, puede eliminarse sin interferir con las otras claves. Sí, estas claves SSH también se pueden proteger con una contraseña.
Puedo estar haciendo algo similar a ti. Actualmente deseo proteger la información personal en una base de datos del servidor web local, por lo que estoy encriptando con una clave pública (almacenada en el servidor web) y descifrándola con una clave privada almacenada en una cookie con corta vida (30 minutos para yo).
En una conexión SSL, esto evitará que la llave caiga en las manos equivocadas y no la almacenará en el servidor. Lo ideal es que verifique que PHP no almacena en caché los valores de las cookies en el servidor, pero incluso si lo hace, esta capa de seguridad aún representa un obstáculo más grande para los atacantes que simplemente robar la base de datos de texto sin formato.
Si este sería un buen enfoque para usted depende de si su aplicación necesita acceder a las credenciales del servidor, incluso cuando los usuarios no inicien sesión a través de la web. En mi caso, el descifrado solo se requiere a través de la aplicación web, por lo que la cookie es suficiente. Sin embargo, si necesita un uso sin supervisión, deberá almacenar la clave privada en el servidor.