¿Cómo asegurar las contraseñas de la base de datos en PHP?

404

Cuando una aplicación PHP realiza una conexión de base de datos, por supuesto, generalmente necesita pasar un nombre de usuario y contraseña. Si estoy usando un inicio de sesión único con permiso mínimo para mi aplicación, entonces el PHP necesita saber ese inicio de sesión y contraseña en alguna parte. ¿Cuál es la mejor manera de asegurar esa contraseña? Parece que escribirlo en el código PHP no es una buena idea.

usuario18359
fuente
1
Para estar totalmente seguro, necesitará configurar una conexión SSL, de lo contrario, cualquier persona en su red aún podrá oler la contraseña que escriba.
Charles Ma
1
¿Se refiere a las contraseñas de usuario o la contraseña de la base de datos utilizada en la cadena de conexión?
Ozgur Ozcitak
44
Contraseña de la base de datos utilizada en la cadena de conexión. ¡Gracias!
user18359

Respuestas:

238

Varias personas interpretaron mal esto como una pregunta sobre cómo almacenar contraseñas en una base de datos. Eso está mal. Se trata de cómo almacenar la contraseña que le permite acceder a la base de datos.

La solución habitual es mover la contraseña del código fuente a un archivo de configuración. Luego, deje la administración y asegure ese archivo de configuración a los administradores de su sistema. De esta forma, los desarrolladores no necesitan saber nada sobre las contraseñas de producción, y no hay registro de la contraseña en su control de origen.

usuario11318
fuente
8
Gracias. Si entiendo esto correctamente, el archivo php tendrá una inclusión en el archivo de configuración, lo que le permitirá usar la contraseña. por ejemplo, creo un archivo llamado 'app1_db_cfg.php' que almacena el nombre de usuario, contraseña y nombre de base de datos. ¡Entonces mi página application.php incluye 'app1_db_cfg.php' y estoy en el negocio!
user18359
28
Estoy de acuerdo en que la configuración debe estar debidamente protegida. Sin embargo, saber cómo hacerlo es asunto de los administradores del sistema, no de los desarrolladores. No estoy de acuerdo con el valor del cifrado seguro en este caso. Si no puede proteger su archivo de configuración, ¿qué le hace pensar que puede proteger sus claves?
user11318
10
Prefiero usar una cuenta de base de datos que solo tenga acceso a la base de datos desde el servidor web. Y luego no me molesto en cifrar la configuración, solo la guardo fuera de la raíz web.
gnud
11
Utilizo una variable de entorno apache para establecer la ruta de modo que incluso la ruta del archivo sea desconocida en el código fuente. Esto también permite tener una contraseña diferente para el desarrollo y la producción en función de la configuración de Apache en el servidor
geedew
15
Tenga en cuenta que incluso los archivos almacenados fuera del directorio web accesible deben ser leídos por el script que los usa. Si alguien incluye ese archivo, luego volca los datos del archivo, verá la contraseña.
Rick Mac Gillis
104

Si está alojado en el servidor de otra persona y no tiene acceso fuera de su raíz web, siempre puede poner su contraseña y / o conexión de base de datos en un archivo y luego bloquear el archivo usando un .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>
Kellen
fuente
3
Gracias, eso era exactamente lo que estaba buscando.
David Gladfelter
28
Definitivamente, pero si alguien tiene acceso de shell, toda su cuenta se ha visto comprometida de todos modos.
Kellen
44
Esta es una mala práctica porque accidentalmente puede confirmar sus credenciales en un repositorio.
Porlune
2
@Ankit: si es posible que una persona no amigable cargue un archivo en el servidor y lo ejecute, entonces el servidor no está configurado correctamente.
Kellen
66
@Porlune: los desarrolladores deben hacer que su sistema de control de versiones ignore el archivo de contraseña, es decir, utilizando un .gitignore. Pero sí, se debe tener cuidado con los archivos que contienen datos confidenciales.
Kellen
45

La forma más segura es no tener la información especificada en su código PHP.

Si está utilizando Apache, eso significa establecer los detalles de conexión en su httpd.conf o archivo de host virtual. Si lo hace, puede llamar a mysql_connect () sin parámetros, lo que significa que PHP nunca generará su información.

Así es como especifica estos valores en esos archivos:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

Luego abres tu conexión mysql así:

<?php
$db = mysqli_connect();

O así:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Lars Nyström
fuente
1
Compruebe los valores correctos de ini_get ('valores predeterminados') php.net/manual/en/class.mysqli.php
Val
44
sí, pero cualquier usuario (o un hacker que esté abusando de un script php mal escrito) puede leer la contraseña a través de ini_get().
Marki555
1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()¿Cómo lidias con esto?
tonix
2
Marki555 dice que un atacante que puede ejecutar código PHP también puede llamar a funciones PHP, lo cual es obviamente cierto e imposible de hacer. También me gustaría agregar que ya no sigo los consejos que doy en esta respuesta, sino que uso variables de entorno. Sin embargo, el concepto es similar: no almacene sus credenciales en el código, sino que las inyecte de alguna manera. Realmente no importa si usa ini_get()o getenv().
Lars Nyström
2
@DeepBlue Si puede inyectar ini_get (), también puede inyectar file_get_contents (anypath). Mientras php tenga una forma de acceder a la contraseña, también lo hará cualquier código malicioso.
varesa
40

Almacénelos en un archivo fuera de la raíz web.

da5id
fuente
29
Y también, como se mencionó en otra parte, fuera del control de la fuente.
Frank Farmer
66
podríamos incluirlo? por ejemplo, en PHP, ¿podemos hacer include('../otherDirectory/configfile.conf')?
mtk
1
Todos están sugiriendo almacenar credenciales fuera de wwwroot. Ok, entiendo el fondo de seguridad. Pero, ¿cómo debería almacenarse en el control de versiones (configuración de muestra)? Por lo general, wwwroot es la raíz del repositorio de git, por lo que si hay algo afuera, estará fuera de VC. Imagínese a un nuevo desarrollador tratando de configurar una instancia local para el desarrollo. ¿Cómo debería saber magia como "tomar este archivo, copiarlo afuera y completarlo"?
El padrino
@TheGodfather La idea es que un nuevo desarrollador debe tener sus propias credenciales para su propio entorno de desarrollo. Aunque es una buena práctica tener un archivo Léame con instrucciones o comentarios en el código que indique cómo debe configurarlo (pero no los datos reales).
PhoneixS
@TheGodfather, archivo léame?
Pacerier
35

Para sistemas extremadamente seguros, encriptamos la contraseña de la base de datos en un archivo de configuración (que a su vez está protegido por el administrador del sistema). Al iniciar la aplicación / servidor, la aplicación solicita al administrador del sistema la clave de descifrado. La contraseña de la base de datos se lee del archivo de configuración, se descifra y se almacena en la memoria para su uso futuro. Todavía no es 100% seguro ya que está almacenado en la memoria descifrada, ¡pero en algún momento debe llamarlo 'lo suficientemente seguro'!

pdavis
fuente
85
¿Qué pasa si el administrador muere?
Radu Murzea
36
@RaduMurzea eso es ridículo. ¿Cuándo has oído hablar de los administradores de Sys muriendo? Son como McDonalds, ¡simplemente aparecen / desaparecen de la nada!
ILikeTacos
13
@Radu Murzea Solo tienes 2 o más administradores, entonces tienes paridad como una matriz de incursiones. Las posibilidades de que más de una unidad falle a la vez son mucho menores.
element11
55
¿Qué pasa cuando los servidores se reinician? ¿Qué pasa con el tiempo que toma despertar al administrador para que escriba la contraseña en ... etc.? lol
John Hunt
1
No estoy seguro de lo que quiere decir con "almacenado en la memoria". Las aplicaciones web PHP generalmente no almacenan nada en la memoria durante más tiempo que el tiempo que lleva responder a una solicitud individual para ver una página.
bdsl
15

Esta solución es general, ya que es útil para aplicaciones de código abierto y cerrado.

  1. Cree un usuario del sistema operativo para su aplicación. Ver http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Cree una variable de entorno del sistema operativo (que no sea de sesión) para ese usuario, con la contraseña
  3. Ejecute la aplicación como ese usuario

Ventajas:

  1. No comprobará sus contraseñas en el control de origen por accidente, porque no puede
  2. No arruinarás accidentalmente los permisos de archivo. Bueno, podrías, pero no afectará esto.
  3. Solo puede leerlo el usuario root o ese usuario. Root puede leer todos sus archivos y claves de cifrado de todos modos.
  4. Si usa cifrado, ¿cómo almacena la clave de forma segura?
  5. Funciona x-plataforma
  6. Asegúrese de no pasar el entorno a procesos secundarios no confiables

Heroku, que tiene mucho éxito, sugiere este método.

Neil McGuigan
fuente
11

si es posible crear la conexión de la base de datos en el mismo archivo donde se almacenan las credenciales. Incluya las credenciales en la declaración de conexión.

mysql_connect("localhost", "me", "mypass");

De lo contrario, es mejor desarmar las credenciales después de la instrucción de conexión, porque las credenciales que no están en la memoria no se pueden leer desde la memoria ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Bob Fanger
fuente
99
Si alguien tiene acceso a la memoria, estás jodido de todos modos. Esta es una falsa seguridad sin sentido. Fuera de la raíz web (o al menos protegida por un .htaccess si no tiene acceso por encima de su raíz web) es la única opción segura.
uliwitness
2
@uliwitness: eso es como decir que solo porque alguien puede cortar la cerradura de su centro de operaciones de red con una antorcha de acetileno significa que la puerta también es falsa seguridad. Mantener la información confidencial vinculada al alcance más estricto posible siempre tiene sentido.
Luke A. Leber el
1
¿Qué tal echo $ db_user o imprimir $ db_pass? Incluso los desarrolladores del mismo equipo no deberían poder descifrar las credenciales de producción. El código no debe contener nada imprimible sobre la información de inicio de sesión.
Mohammed Joraid
8

Sus opciones son un poco limitadas, ya que dice que necesita la contraseña para acceder a la base de datos. Un enfoque general es almacenar el nombre de usuario y la contraseña en un archivo de configuración separado en lugar del script principal. Luego, asegúrese de almacenarlo fuera del árbol web principal. Eso fue si hay un problema de configuración web que deja que sus archivos php simplemente se muestren como texto en lugar de ejecutarse, no ha expuesto la contraseña.

Aparte de eso, está en la línea correcta con un acceso mínimo para la cuenta que se está utilizando. Añadir a eso

  • No use la combinación de nombre de usuario / contraseña para nada más
  • Configure el servidor de la base de datos para que solo acepte conexiones del host web para ese usuario (localhost es aún mejor si el DB está en la misma máquina) De esa manera, incluso si las credenciales están expuestas, no serán de utilidad para nadie a menos que tengan otro acceso al máquina.
  • Ofusque la contraseña (incluso ROT13 lo hará) no ofrecerá mucha defensa si algunos obtienen acceso al archivo, pero al menos evitará la visualización casual de él.

Peter

Vagnerr
fuente
8

Si está utilizando PostgreSQL, busca las ~/.pgpasscontraseñas automáticamente. Vea el manual para más información.

Jim
fuente
8

Anteriormente almacenamos el usuario / pase de DB en un archivo de configuración, pero desde entonces hemos alcanzado el modo paranoico, adoptando una política de Defensa en profundidad .

Si su aplicación se ve comprometida, el usuario tendrá acceso de lectura a su archivo de configuración y, por lo tanto, existe la posibilidad de que un cracker lea esta información. Los archivos de configuración también pueden quedar atrapados en el control de versiones o copiarse en servidores.

Hemos pasado a almacenar las variables de entorno de usuario / pase establecidas en Apache VirtualHost. Esta configuración solo puede ser leída por el usuario root. Esperemos que su usuario de Apache no se ejecute como usuario root.

La desventaja con esto es que ahora la contraseña está en una variable PHP global.

Para mitigar este riesgo, tenemos las siguientes precauciones:

  • La contraseña está encriptada.Extendemos la clase PDO para incluir lógica para descifrar la contraseña. Si alguien lee el código donde establecemos una conexión, no será obvio que la conexión se establece con una contraseña cifrada y no con la contraseña en sí.
  • La contraseña cifrada se mueve de las variables globales a una variable privada. La aplicación hace esto inmediatamente para reducir la ventana de que el valor está disponible en el espacio global.
  • phpinfo()está desactivado. PHPInfo es un objetivo fácil para obtener una visión general de todo, incluidas las variables de entorno.
Courtney Miles
fuente
6

Coloque la contraseña de la base de datos en un archivo, haga que sea de solo lectura para el usuario que sirve los archivos.

A menos que tenga algún medio para permitir que el proceso del servidor php acceda a la base de datos, esto es prácticamente todo lo que puede hacer.

Chris
fuente
5

Si habla de la contraseña de la base de datos, a diferencia de la contraseña que proviene de un navegador, la práctica estándar parece ser poner la contraseña de la base de datos en un archivo de configuración de PHP en el servidor.

Solo necesita asegurarse de que el archivo php que contiene la contraseña tenga los permisos adecuados. Es decir, debe ser legible solo por el servidor web y por su cuenta de usuario.

Jason Wadsworth
fuente
1
Lamentablemente, phpinfo () puede leer el archivo de configuración de PHP y si alguien deja algún script de prueba detrás, un atacante afortunado podría leer la contraseña. Probablemente sea mejor dejar la contraseña de conexión en un archivo fuera de la raíz del servidor web. Entonces, la única forma de acceder es con un shell o ejecutando código arbitrario, pero en ese escenario toda la seguridad se pierde de todos modos.
MarioVilas
5

Simplemente ponerlo en un archivo de configuración en algún lugar es la forma en que generalmente se hace. Solo asegúrate de que:

  1. no permitir el acceso a la base de datos desde cualquier servidor fuera de su red,
  2. tenga cuidado de no mostrar accidentalmente la contraseña a los usuarios (en un mensaje de error o mediante archivos PHP que se sirven accidentalmente como HTML, etc.)
Marijn
fuente
5

Lo hemos resuelto de esta manera:

  1. Use memcache en el servidor, con conexión abierta desde otro servidor de contraseñas.
  2. Guarde en la memoria caché la contraseña (o incluso todo el archivo password.php cifrado) más la clave de descifrado.
  3. El sitio web llama a la clave memcache que contiene la frase de contraseña del archivo de contraseña y descifra en la memoria todas las contraseñas.
  4. El servidor de contraseñas envía un nuevo archivo de contraseña cifrada cada 5 minutos.
  5. Si usa password.php encriptado en su proyecto, realiza una auditoría, que verifica si este archivo se tocó externamente, o si se vio. Cuando esto sucede, puede limpiar automáticamente la memoria, así como cerrar el servidor para acceder.
Asi Azulay
fuente
4

Un truco adicional es usar un archivo de configuración de PHP separado que se vea así:

<?php exit() ?>

[...]

Plain text data including password

Esto no le impide establecer las reglas de acceso correctamente. Pero en el caso de que su sitio web sea pirateado, un "requerir" o un "incluir" simplemente saldrá del script en la primera línea, por lo que es aún más difícil obtener los datos.

Sin embargo, nunca permita que los archivos de configuración se encuentren en un directorio al que se pueda acceder a través de la web. Debe tener una carpeta "Web" que contenga su código de controlador, css, imágenes y js. Eso es todo. Todo lo demás va en carpetas sin conexión.

e-satis
fuente
pero entonces, ¿cómo lee el script php las credenciales almacenadas en el archivo?
Christopher Mahan el
3
Utiliza fopen (), como para un archivo de texto normal.
e-satis
2
@ e-satis ok, evitará que el hacker haga require/ includepero ¿cómo evitar que lo haga fopen?
dmnc el
"Esto no le impide establecer las reglas de acceso correctamente"
e-satis
@ e-satis, esto es bastante inteligente. Me pregunto por qué nadie lo había pensado. Sin embargo , sigue siendo vulnerable al problema de copia del editor. feross.org/cmsploit
Pacerier
4

¡La mejor manera es no almacenar la contraseña en absoluto!
Por ejemplo, si está en un sistema Windows y se conecta a SQL Server, puede usar la autenticación integrada para conectarse a la base de datos sin una contraseña, utilizando la identidad del proceso actual.

Si necesita conectarse con una contraseña, primero encripte , usando un cifrado seguro (por ejemplo, usando AES-256, y luego proteja la clave de cifrado, o usando un cifrado asimétrico y haga que el sistema operativo proteja el certificado), y luego guárdelo en un archivo de configuración (fuera del directorio web) con ACL fuertes .

Ávido
fuente
3
No tiene sentido volver a cifrar la contraseña . Alguien que pueda obtener la contraseña no cifrada también puede obtener la frase de contraseña necesaria para descifrar la contraseña. Sin embargo, usar ACL y .htaccess es una buena idea.
uliwitness
2
@uliwitness Creo que puede haber entendido mal: ¿qué quiere decir con "cifrar de nuevo "? Es solo el cifrado. Y no desea utilizar frases de contraseña (destinadas al uso humano) para encriptarlo, sino una administración de claves bastante sólida, por ejemplo, protegida por el sistema operativo, de tal manera que simplemente acceder al sistema de archivos no otorgue acceso a la clave.
AviD
3
El cifrado no es mágico: en lugar de proteger la clave AES con ACL, puede almacenar la contraseña allí. No hay diferencia entre acceder a la clave AES o la contraseña descifrada, el cifrado en este contexto es solo aceite de serpiente.
MarioVilas
@MarioVilas whaat? Si la contraseña está encriptada, con la clave de encriptación protegida por el sistema operativo, ¿cómo no hay diferencia? El cifrado no es mágico, solo compacta todo el secreto en la clave de cifrado más pequeña. Apenas aceite de serpiente, en este contexto solo está trasladando todo ese secreto al sistema operativo.
AviD
66
@AviD ¿por qué el sistema operativo puede proteger la clave pero no los datos en sí? Respuesta: puede proteger a ambos, por lo que el cifrado realmente no ayuda. Sería diferente si solo se almacenaran los datos y la clave de cifrado se derivara, por ejemplo, de una contraseña que un usuario tenía que escribir .
MarioVilas