Ocultar contraseña en scripts de shell

23

¿Cómo puedo ocultar una contraseña en scripts de shell? Hay una serie de scripts que están accediendo a la base de datos. Si abrimos el script, otros también conocen el nombre de usuario y la contraseña. Entonces, si alguien sabe cómo esconderse, hágamelo saber.

Tengo una manera: coloque la contraseña en un archivo y haga que el archivo esté oculto y nadie va a acceder al archivo (cambie los permisos y use el archivo en el script mientras accede a la base de datos).

arun
fuente

Respuestas:

35

Primero , como ya han dicho varias personas, es esencial mantener las credenciales separadas del guión. (Además de una mayor seguridad, también significa que puede reutilizar el mismo script para varios sistemas con credenciales diferentes).

En segundo lugar , debe considerar no solo la seguridad de las credenciales, sino también el impacto si esas credenciales se ven comprometidas. No debe tener una sola contraseña para todo el acceso a la base de datos, debe tener diferentes credenciales con diferentes niveles de acceso. Podría, por ejemplo, tener un usuario de base de datos que tenga la capacidad de realizar una búsqueda en la base de datos; ese usuario debería tener acceso de solo lectura. Otro usuario puede tener permiso para insertar nuevos registros, pero no para eliminarlos. Un tercero puede tener permiso para eliminar registros.

Además de restringir los permisos para cada cuenta, también debe tener restricciones sobre dónde se puede usar cada cuenta. Por ejemplo, no se debe permitir que la cuenta utilizada por su servidor web se conecte desde ninguna otra dirección IP que no sea la del servidor web. Una cuenta con permisos de raíz completos para la base de datos debe estar muy restringida en términos de dónde se puede conectar y nunca debe usarse de manera interactiva. También considere usar procedimientos almacenados en la base de datos para restringir exactamente lo que puede hacer cada cuenta.

Estas restricciones deben implementarse en el lado del servidor DB del sistema, de modo que incluso si el lado del cliente se ve comprometido, las restricciones no se pueden modificar. (Y, obviamente, el servidor de base de datos debe protegerse con firewalls, etc., además de la configuración de base de datos ...)

En el caso de una cuenta de base de datos que solo tiene acceso limitado de solo lectura, y solo desde una dirección IP en particular, es posible que no necesite más credenciales que eso, dependiendo de la sensibilidad de los datos y la seguridad del host del script se está ejecutando desde. Un ejemplo puede ser un formulario de búsqueda en su sitio web, que se puede ejecutar con un usuario al que solo se le permite usar un procedimiento almacenado que extrae solo la información que se presentará en la página web. En este caso, agregar una contraseña realmente no confiere ninguna seguridad adicional, ya que esa información ya debe ser pública, y el usuario no puede acceder a ningún otro dato que sea más confidencial.

También asegúrese de que la conexión a la base de datos se realice mediante TLS, o cualquier persona que escuche en la red puede obtener sus credenciales.

Tercero , considere qué tipo de credenciales usar. Las contraseñas son solo una forma, y ​​no las más seguras. En su lugar, podría usar alguna forma de par de claves pública / privada, o AD / PAM o similares.

Cuarto , considere las condiciones bajo las cuales se ejecutará el script:

Si se ejecuta de forma interactiva, debe ingresar la contraseña, o la contraseña de la clave privada, o la clave privada, o iniciar sesión con un ticket Kerberos válido, cuando lo ejecute; en otras palabras, el script debe obtener su credenciales directamente de usted en el momento en que lo ejecuta, en lugar de leerlas de algún archivo.

Si se ejecuta desde un servidor web, considere configurar las credenciales en el momento en que inicie el servidor web. Un buen ejemplo aquí son los certificados SSL: tienen un certificado público y una clave privada, y la clave privada tiene una contraseña. Puede almacenar la clave privada en el servidor web, pero aún necesita ingresar la contraseña cuando inicie Apache. También podría tener las credenciales en algún tipo de hardware, como una tarjeta física o un HSM, que se pueden quitar o bloquear una vez que se inicia el servidor. (Por supuesto, la desventaja de este método es que el servidor no puede reiniciarse solo si algo sucede. Preferiría esto al riesgo de que mi sistema se vea comprometido, pero su kilometraje puede variar ...)

Si el script se ejecuta desde cron, esta es la parte difícil. No desea tener las credenciales en cualquier lugar de su sistema donde alguien pueda acceder a ellas, pero sí quiere tenerlas por ahí para que su script pueda acceder a ellas, ¿verdad? Bueno, no del todo bien. Considere exactamente lo que está haciendo el guión. ¿Qué permisos necesita en la base de datos? ¿Se puede restringir para que no importe si la persona equivocada se conecta con esos permisos? ¿Puede ejecutar el script directamente en el servidor de base de datos al que nadie más tiene acceso, en lugar de hacerlo desde el servidor que tiene otros usuarios? Si, por alguna razón que no se me ocurre, absolutamente debe tener el script ejecutándose en un servidor inseguro y debe ser capaz de hacer algo peligroso / destructivo ... ahora es un buen momento para repensar su arquitectura.

Quinto , si valora la seguridad de su base de datos, no debería ejecutar estos scripts en servidores a los que otras personas tienen acceso. Si alguien ha iniciado sesión en su sistema, tendrá la posibilidad de obtener sus credenciales. Por ejemplo, en el caso de un servidor web con un certificado SSL, existe al menos una posibilidad teórica de que alguien pueda obtener root y acceder al área de memoria del proceso httpd y extraer las credenciales. Ha habido al menos un exploit en los últimos tiempos en el que esto podría hacerse a través de SSL, sin siquiera requerir que el atacante inicie sesión.

También considere usar SELinux o apparmor o lo que esté disponible para su sistema para restringir qué usuarios pueden hacer qué. Permitirán que no permita que los usuarios intenten conectarse a la base de datos, incluso si logran obtener acceso a las credenciales.

Si todo esto le parece excesivo , y no puede permitirse el lujo o no tiene tiempo para hacerlo, entonces, en mi opinión (arrogante y elitista), no debería almacenar nada importante o sensible en su base de datos. Y si no está almacenando nada importante o sensible, entonces el lugar donde almacena sus credenciales tampoco es importante, en cuyo caso, ¿por qué usar una contraseña?

Por último , si no puede evitar almacenar algún tipo de credenciales, podría tener las credenciales de solo lectura y propiedad de root y root podría otorgar la propiedad de forma extremadamente temporal cuando un script lo solicite (porque su script no debe ser ejecutar como root a menos que sea absolutamente necesario, y conectarse a una base de datos no lo hace necesario). Pero todavía no es una buena idea.

Jenny D
fuente
99
No arrogante y elitista en absoluto. O si no, yo también. "¿Cómo puedo proteger mis joyas en caso de que un ladrón ingrese?" "Póngalo en una caja fuerte que esté atornillada / soldada en su lugar". "Eso es demasiado problema, solo conseguiré una caja fuerte portátil y colgaré la llave de un gancho". "Entonces no te molestes en usar una caja fuerte". Consejo eminentemente sensato.
Comodín
12

En primer lugar, si hay alguna forma de cambiar las cosas para evitar tener que guardar una contraseña dentro o junto a un script, en primer lugar, debe hacer todo lo posible para hacerlo. La respuesta de Jenny D contiene muchos buenos consejos al respecto.

De lo contrario, su idea de colocar la contraseña en un archivo separado con permisos restringidos es más o menos eso. Puede, por ejemplo, obtener ese archivo del script principal:

. /usr/local/etc/secret-password-here

También puede restringir los permisos del script principal para que solo las personas autorizadas puedan ejecutarlo, pero probablemente sea mejor hacer lo que sugiere y almacenar solo la contraseña en un archivo restringido. De esa manera, puede permitir la inspección del código en sí (sin secretos confidenciales), el control de versiones y la copia del script más fácilmente, etc.

Celada
fuente
@BasileStarynkevitch ah, pero veo que también dice " /usr/local/etcpuede ser un enlace simbólico a /etc/local". Me lo perdí. Entonces también tienes razón, pero es MAYO, así que es opcional. Pero sí, no importa mucho, y las preferencias personales.
Celada
1
Excepto que estoy haciendo una copia de seguridad /etc/ pero no /usr/local/ (lo cual supongo que se puede reconstruir después del bloqueo del disco)
Basile Starynkevitch
punto justo sobre las copias de seguridad
Celada
3

Otras respuestas han abordado el cómo , pero consideraré si . Dependiendo del tipo de base de datos a la que se conectan sus usuarios, es posible que ya tenga un mecanismo adecuado que ya utilizan esos programas cliente, en cuyo caso asegúrese de usarlos (estoy pensando en ~/.mysqlrco ~/.pgpass).

Si le está dando a varios usuarios la capacidad de acceder a la base de datos para realizar consultas específicas utilizando una cuenta compartida, entonces probablemente no debería hacerlo. En su lugar, asegúrese de que tengan cuentas en la base de datos y que esas cuentas no tengan más permisos de los que necesitan (probablemente lean en gran parte y tengan muy poco acceso de escritura). Si necesitan realizar consultas específicas en ciertas tablas a las que de otra manera no pueden acceder, proporcione procedimientos almacenados SECURTY DEFINERpara permitirles hacerlo.

Si ninguna de las anteriores que evita que necesitan almacenar credenciales, a continuación, lea las otras respuestas aquí.

Toby Speight
fuente
1

Su idea de ocultar la contraseña en un lugar inaccesible podría estar bien dependiendo de las circunstancias.

Si la información es separada, eso significa que la edición simple del archivo, por ejemplo, durante una revisión de código con un colega no la mostrará. Pero tenga en cuenta que cualquier persona con acceso a su cuenta puede encontrar fácilmente dicho archivo. He utilizado un subdirectorio de ~/.sshpara tales fines, por la sencilla razón de que se sshqueja si los derechos de acceso ~/.sshno están lo suficientemente restringidos.

Sin embargo, hay otras cosas que puede hacer para evitar que se echen un vistazo al nombre de usuario y / o contraseña.

Ofuscación : si no desea que nadie lea el nombre de usuario o la contraseña mientras edita un script, puede ponerlo en el texto pero no como texto sin formato, sino ofuscado. Si la versión ofuscada es lo suficientemente larga como para evitar su memorización por parte de alguien que la mira, no se puede saber aunque el método de descifrado y la clave estén a la vista. Esto, por supuesto, aún sería evitado trivialmente por alguien que tenga acceso a su cuenta.

Usando GPG :

Un poco mejor, pero aún no es una prueba completa contra los ataques del usuario raíz en su sistema, es encriptar los pares de nombre de usuario / contraseña en un archivo gpgpúblico y hacer que el script recupere el contenido del archivo (si es posible, le pedirá una contraseña). en caché / expirado). Utilizo la tarjeta ggp para que cuando deje mi computadora portátil pero saque la tarjeta, no sea posible el acceso, incluso si el pin todavía estuviera en caché. Al menos si ejecuto 20 veces en unos minutos, tengo que proporcionar el pin solo una vez.

La seguridad siempre parece estar inversamente relacionada con la conveniencia (configuración y uso).

Anthon
fuente
0

Hay una manera de almacenar las contraseñas en un script bash, pero debe cifrar y ofuscar el script para que nadie pueda leerlo o ejecutar ningún tipo de depurador para ver exactamente lo que está haciendo. Para cifrar y ofuscar un script bash / shell y hacer que sea realmente ejecutable, intente copiarlo y pegarlo aquí:

http://www.kinglazy.com/shell-script-encryption-kinglazy-shieldx.htm

En la página anterior, todo lo que tiene que hacer es enviar su script (puede enviar primero un script de muestra para su tranquilidad). Se generará un archivo zip para usted. Haga clic derecho en el enlace de descarga y copie la URL que se le proporcionó. Luego, vaya a su cuadro UNIX y realice los siguientes pasos.

Instalación:

  1. wget enlace al archivo zip

  2. descomprima el archivo zip recién descargado

  3. cd / tmp / KingLazySHIELD

  4. ./install.sh / var / tmp / KINGLAZY / SHIELDX- (your-script-name) / home / (your-username) -force

Lo que el comando de instalación anterior hará por usted es:

  1. Instalará la versión encriptada de su script en el directorio / var / tmp / KINGLAZY / SHIELDX- (your-script-name).

  2. Colocará un enlace a este script encriptado en el directorio que especifique en reemplazo de / home / (su-nombre de usuario); de esa manera, le permite acceder fácilmente al script sin tener que escribir la ruta absoluta.

  3. Garantiza que NADIE pueda modificar el guión: cualquier intento de modificar el guión cifrado lo dejará inoperativo ... hasta que esos intentos se detengan o eliminen. Incluso se puede configurar para notificarle cuando alguien intente hacer algo con el script que no sea ejecutarlo ... es decir, intentos de piratería o modificación.

  4. Asegura absolutamente NADIE puede hacer copias de él. Nadie puede copiar su secuencia de comandos en una ubicación aislada e intentar jugar con ella para ver cómo funciona. Todas las copias del script deben ser enlaces a la ubicación original que especificó durante la instalación (paso 4).

NOTA:

No creo que esto funcione para scripts interactivos que soliciten al usuario una respuesta. Los valores deben estar codificados en el script. El cifrado garantiza que nadie pueda ver esos valores, por lo que no debe preocuparse por eso.

AncientMinds
fuente
0

Otra solución, sin tener en cuenta la seguridad (también creo que es mejor mantener las credenciales en otro archivo o en una base de datos) es cifrar la contraseña con gpg e insertarla en el script.

Utilizo un par de claves gpg sin contraseña que guardo en un usb. (Nota: cuando exporte este par de claves, no use --armor, expórtelos en formato binario).

Primero encripte su contraseña:

echo -n "pAssw0rd" | gpg --armor --no-default-keyring --keyring /media/usb/key.pub --recipient someone@mail.com --encrypt

Eso imprimirá la contraseña cifrada gpg en la salida estándar. Copie el mensaje completo y agregue esto al script:

password=$(gpg --batch --quiet --no-default-keyring --secret-keyring /media/usb/key.priv --decrypt <<EOF 
-----BEGIN PGP MESSAGE-----

hQEMA0CjbyauRLJ8AQgAkZT5gK8TrdH6cZEy+Ufl0PObGZJ1YEbshacZb88RlRB9
h2z+s/Bso5HQxNd5tzkwulvhmoGu6K6hpMXM3mbYl07jHF4qr+oWijDkdjHBVcn5
0mkpYO1riUf0HXIYnvCZq/4k/ajGZRm8EdDy2JIWuwiidQ18irp07UUNO+AB9mq8
5VXUjUN3tLTexg4sLZDKFYGRi4fyVrYKGsi0i5AEHKwn5SmTb3f1pa5yXbv68eYE
lCVfy51rBbG87UTycZ3gFQjf1UkNVbp0WV+RPEM9JR7dgR+9I8bKCuKLFLnGaqvc
beA3A6eMpzXQqsAg6GGo3PW6fMHqe1ZCvidi6e4a/dJDAbHq0XWp93qcwygnWeQW
Ozr1hr5mCa+QkUSymxiUrRncRhyqSP0ok5j4rjwSJu9vmHTEUapiyQMQaEIF2e2S
/NIWGg==
=uriR
-----END PGP MESSAGE-----
EOF)

De esta manera, solo si el usb está montado en el sistema, la contraseña se puede descifrar. Por supuesto, también puede importar las claves en el sistema (menos seguro o sin seguridad) o puede proteger la clave privada con contraseña (por lo que no puede automatizarse).

Juanu
fuente
-2
#!/bin/bash
unset username
unset password
unset dbname
echo -n "username:"
read username
echo -n "dbname:"
read dbname
prompt="password:"

    while IFS= read -p "$prompt" -r -s -n 1 char
            do
                    if [[ $char == $'\0' ]]
                            then
                                    break
                    fi
                    prompt='*'
                    password+="$char"
            #       read -s -p "Enter Password: "  pswd
            #       echo -e "\nYour password is: " $pswd
            done
arun
fuente
3
He sangrado su código, ¿tal vez podría explicar lo que está tratando de hacer?
Archemar
-6

No creo que alguna vez debas guardar la contraseña. No puedo pensar en una sola buena razón para eso. Por el contrario, debe almacenar un hash salado de esa contraseña, alguna cadena que es producida de manera confiable por alguna función cuando la contraseña original se pasa como entrada, pero nunca la contraseña .

mikeserv
fuente
55
No tengo claro cómo esto resolverá el problema de a) poder conectarse a un servicio que requiera una contraseña, yb) los usuarios puedan ver el script y así poder averiguar los detalles de autenticación, si esas son contraseñas o no
Jenny D
1
Usted dice saber mi respuesta antes de que la haya escrito.
Jenny D
1
He escrito mi respuesta ahora. Lo que estaba tratando de obtener de usted fue en parte mi quinto punto: una vez que las credenciales se almacenan en la memoria, no están completamente seguras de un atacante con acceso al servidor. Además, su breve respuesta no fue muy útil, aunque no sea incorrecta. Estoy pensando en señalarlo la próxima vez que alguien se queje de que nosotros en ServerFault no somos tan amables como la gente de Unix / Linux :-)
Jenny D
2
@JennyD: una vez que la credibilidad está en la memoria, ciertamente no necesita quedarse allí, y esa es una muy buena razón para tratar con hashes de todos modos. Aún así, felizmente representaré los estándares de cortesía de la comunidad como su ejemplo en general, de hecho, soy muy conocido por ese rasgo.
mikeserv
44
Después de su gran discusión, me gustaría mencionar en caso de que haya algún malentendido de que fui yo quien votó en contra, no Jenny. Y la razón no fue una opinión sobre si es una buena idea usar un certificado y clave privada o contraseña ingresada interactivamente o hacer lo que el OP quería o lo que sea. Fue porque la respuesta tal como está es incorrecta: almacenar un hash salado de la contraseña como credencial del cliente no es una cosa: los hash salados son algo que se mantiene al final de la conexión que verifica la autenticación, no en el lado que lo está enviando.
Celada