Comment passer un mot de passe à un processus enfant?

18

La transmission d'un mot de passe en ligne de commande (à un processus enfant démarré à partir de mon programme) est connue pour être non sécurisée (car elle peut être vue même par d'autres utilisateurs avec la commande ps). Est-il correct de le passer comme variable d'environnement à la place?

Que puis-je utiliser pour le passer? (À l'exception de la variable d'environnement), la solution la plus simple semble utiliser un tuyau, mais cette solution la plus simple n'est pas facile.

Je programme en Perl.

porton
la source
2
Pourquoi n'est-ce pas facile? Il n'est pas nécessaire que ce soit un canal séparé / nommé, juste stdin / out normal fera l'affaire ... cela ne devrait pas poser trop de problèmes dans aucune langue. Vous pouvez le mettre dans un fichier de configuration simple si vous pouvez vous assurer qu'il n'est lisible que par les processus d'intérêt (ce qui est beaucoup plus difficile qu'il n'y paraît).
frostschutz
1
Si vous n'appelez pas exec chez l'enfant, vous avez toujours une copie du mot de passe sans rien faire.
James Youngman

Réponses:

26

Les arguments de processus sont visibles pour tous les utilisateurs, mais l'environnement n'est visible que pour le même utilisateur ( au moins sous Linux , et je pense sur toutes les variantes Unix modernes). Il est donc sûr de passer un mot de passe via une variable d'environnement. Si quelqu'un peut lire vos variables d'environnement, il peut exécuter des processus comme vous, donc c'est déjà fini.

Le contenu de l'environnement risque de fuir indirectement, par exemple si vous exécutez psune enquête et copiez-collez accidentellement le résultat, y compris les variables d'environnement confidentielles dans un lieu public. Un autre risque est que vous passiez la variable d'environnement à un programme qui n'en a pas besoin (y compris les enfants du processus qui a besoin du mot de passe) et que ce programme expose ses variables d'environnement car il ne s'attendait pas à ce qu'elles soient confidentielles. La gravité de ces risques de fuite secondaire dépend de ce que fait le processus avec le mot de passe (combien de temps dure-t-il? Exécute-t-il des sous-processus?).

Il est plus facile de s'assurer que le mot de passe ne fuit pas accidentellement en le faisant passer par un canal qui n'est pas conçu pour être écouté, comme un tuyau. C'est assez facile à faire du côté de l'envoi. Par exemple, si vous avez le mot de passe dans une variable shell, vous pouvez simplement faire

echo "$password" | theprogram

si theprogramattend le mot de passe sur son entrée standard. Notez que cela est sûr car il echos'agit d'une fonction intégrée; ce ne serait pas sûr avec une commande externe car l'argument serait exposé en pssortie. Une autre façon d'obtenir le même effet est avec un document ici:

theprogram <<EOF
$password
EOF

Certains programmes qui nécessitent un mot de passe peuvent être invités à le lire à partir d'un descripteur de fichier spécifique. Vous pouvez utiliser un descripteur de fichier autre que l'entrée standard si vous avez besoin d'une entrée standard pour autre chose. Par exemple, avec gpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

Si le programme ne peut pas être invité à lire à partir d'un descripteur de fichier mais peut être invité à lire à partir d'un fichier, vous pouvez lui dire de lire à partir d'un descripteur de fichier en utilisant un nom de fichier comme `/ dev / fd / 3.

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

Dans ksh, bash ou zsh, vous pouvez le faire de manière plus concise grâce à la substitution de processus.

theprogram --password-from-file=<(echo "$password")
Gilles 'SO- arrête d'être méchant'
la source
Sous Solaris 9 et /usr/ucb/psversions antérieures, la racine setuid permettait de lire et d'afficher les variables d'environnement d'autres processus - cela a été supprimé dans Solaris 10, donc la réponse "toutes les autres variantes Unix modernes" ci-dessus s'applique aux versions Solaris de 2005 et ultérieures.
alanc
@alanc En effet, je ne considère pas Solaris <10 comme moderne de nos jours. Solaris 9 est presque aussi vieux que Windows XP!
Gilles 'SO- arrête d'être méchant'
Gilles: il y a des jours que j'ai du mal à considérer Solaris 10 moderne maintenant que Solaris 11 est sorti depuis plus de 5 ans, donc je comprends parfaitement et suis d'accord, mais malheureusement je sais que certaines personnes utilisent toujours Solaris 8 ou 9.
alanc
10

Au lieu de passer le mot de passe directement via un argument ou une variable d'environnement

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

utilisez le même argument ou la même variable d'environnement pour passer un nom de fichier :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Ensuite , vous pouvez passer soit un fichier régulier protégé permission (si cela ne vous protégera pas d'autres processus en cours d' exécution sous le même utilisateur), ou /dev/stdinet conduite dans (qui AFAIK vous protégera des autres processus en cours d' exécution sous le même utilisateur):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

Si vous l'utilisez /dev/stdinici, il est impératif que ce soit une pipe . S'il s'agit d'un terminal, il sera lisible par d'autres processus exécutés sous le même utilisateur.

Si vous avez déjà besoin d'utiliser votre /dev/stdinpour autre chose, vous pouvez utiliser la substitution de processus si vous êtes sur un shell qui le prend en charge, ce qui est essentiellement équivalent à l'utilisation de tuyaux:

./passwd_receiver <(echo PASSWORD)

Les canaux nommés (FIFO) peuvent sembler identiques, mais ils sont interceptables.

Ces solutions ne sont pas non plus parfaitement sécurisées , mais elles peuvent être suffisamment proches à condition que vous ne soyez pas sur un système à mémoire limitée qui échange beaucoup.

Idéalement, vous devriez lire ces fichiers (pipe est un fichier aussi) dans la mémoire marquée avec mlock (2) comme non échangeable, ce que font généralement les programmes de gestion de mot de passe tels que gnupg.

Remarques:

  1. En passant les numéros de FileDescriptor est théoriquement juste bon comme fichier en tant que noms de fichiers passe, mais les noms de fichiers sont plus pratiques, parce que <()vous donne un nom de fichier, pas un numéro de FileDescriptor (et coprocs vous donnent filedescriptors marqué FD_CLOEXEC , ce qui rend ces filedescriptors inutilisables dans ce contexte).

  2. Si vous êtes sur un système Linux où
    /proc/sys/kernel/yama/ptrace_scopeest défini sur 0, puis AFAIK, il n'y a pas de moyen à toute épreuve de vous protéger contre d'autres processus exécutés sous le même utilisateur (ils peuvent utiliser ptrace pour se connecter à votre processus et lire votre mémoire)

  3. Si vous avez seulement besoin de garder votre mot de passe à l'écart des processus exécutés sous différents utilisateurs (non root), les arguments, les variables d'environnement, les canaux et les fichiers protégés par des autorisations feront l'affaire.

PSkocik
la source
7

Non, les variables d'environnement sont également faciles à lire et fuient vers les processus enfants. passer à l'aide d'un tuyau.

Jasen
la source
2
"variables d'environnement ... fuite vers les processus enfants" C'est tout l'intérêt d'utiliser une variable d'environnement. Ils seraient inutiles s'ils n'étaient pas hérités. "Les variables d'environnement sont également faciles à lire", non, elles ne le sont pas.
Patrick
2
Lisez la variable, désactivez-la. C'est pas difficile. Et vous pouvez utiliser le même argument à propos du tuyau. Si le canal n'est pas lu, il est transmis au processus enfant et le processus enfant pourrait le lire et obtenir le mot de passe.
Patrick
1
@Patrick Les moyens documentés de suppression des variables d'environnement ne nettoient pas nécessairement la valeur de l'endroit où pselle /procpeut être vue.
zwol
1
Certains systèmes vous permettent-ils de lire les variables d'environnement de processus arbitraires? Je ne pense pas que Linux le permette pour les processus appartenant à d'autres, et si vous êtes le même utilisateur, vous pouvez simplement ptrace()cibler et lire sa mémoire de toute façon.
ilkkachu
5
Cette réponse est fausse. Les variables d'environnement ne peuvent pas être lues par d'autres utilisateurs.
Gilles 'SO- arrête d'être méchant'
1

Si rien d'autre ne vous convient, pensez au service Linux Key Retention (porte-clés du noyau).

Commencez par: security / keys.txt . L'un des trousseaux de clés par défaut peut être cloné entre les processus parent et enfant.

Ce n'est pas la solution la plus simple, mais elle est là et semble être maintenue et utilisée (elle a également été impliquée dans un bug Android l'année dernière.)

Je ne connais pas son statut "politique", mais j'avais un besoin similaire, et j'ai commencé à travailler sur une liaison Guile. N'ont pas rencontré de support Perl préexistant.

kzurell
la source