Masquage de l'entrée utilisateur sur le terminal dans le script Linux


121

J'ai un script bash comme le suivant:

#!/bin/bash

echo "Please enter your username";
read username;

echo "Please enter your password";
read password;

Je veux que lorsque l'utilisateur tape le mot de passe sur le terminal, il ne doit pas être affiché (ou quelque chose comme *******) doit être affiché). Comment y parvenir?


2
Note générale juste pour éviter toute confusion: ce nom d'utilisateur / mot de passe n'a rien à voir avec le nom d'utilisateur / mot de passe linux - je cherche juste un moyen de cacher les données que l'utilisateur tape lors de la "lecture du mot de passe".

J'ai ajouté une mise à jour pour si vous voulez avoir de la fantaisie en sortant *pendant qu'ils saisissent le mot de passe
SiegeX

Merci beaucoup. Une question si quelqu'un sait - est-ce que cela l'empêchera automatiquement d'entrer dans .bash_history?


2
Je ne pense pas que ce sera le cas, bash_history ne capture que votre commande, ce qui se passe après l'exécution de votre commande, il ne capture pas.
Andreas Wong

Réponses:


272

Fournissez simplement -s à votre appel de lecture comme ceci:

$ read -s PASSWORD
$ echo $PASSWORD

9
J'aime mieux cette façon. Je vous voterais si je n'atteignais pas ma limite quotidienne
SiegeX

4
Pour fournir le contexte: -sn'affiche rien pendant la saisie de l'entrée. ( -sest une extension non POSIX, donc tous les shells ne la prennent pas en charge, comme le ashshell fourni avec BusyBox; utilisez l' ssty -echoapproche dans de tels shells)
mklement0

3
@electron Rien dans la manpage ne suggère en fait que -sla couleur du texte soit la même que la couleur d'arrière-plan. Il "résonne en silence". ss64.com/bash/read.html Silent mode. If input is coming from a terminal, characters are not echoed.
Andreas Wong

2
@electron J'ai testé sur ma box, non seulement ça ne déplace pas le curseur, quand j'essaye de mettre en évidence la ligne où j'ai tapé mon mot de passe, je n'arrive pas à le coller plus tard. Les deux devraient se produire si ce que dit le livre est vrai. J'imagine peut-être une saveur différente de shell (j'utilisais bash 4.1.2 (1)).
Andreas Wong

1
@DominykasMostauskis ouais mais l'étiquette est pour bash, donc la solution. Il y a probablement des tonnes de variantes de shell où cela ne fonctionne pas :)
Andreas Wong

25

Mettre à jour

Au cas où vous voudriez avoir de la fantaisie en produisant un *pour chaque caractère qu'ils tapent, vous pouvez faire quelque chose comme ceci (en utilisant la read -ssolution d' andreas ):

unset password;
while IFS= read -r -s -n1 pass; do
  if [[ -z $pass ]]; then
     echo
     break
  else
     echo -n '*'
     password+=$pass
  fi
done

Sans être fantaisiste

echo "Please enter your username";
read username;

echo "Please enter your password";
stty -echo
read password;
stty echo

Cela devrait être fait IFS=$'\n'pour que vous puissiez finir de taper le mot de passe. Sinon sympa; très intelligent.
sorpigal

2
Pas besoin de définir IFS=$'\n'car le délimiteur par défaut de read est -d $'\n'. L'instruction if à casser sur une chaîne nulle, qui se produit sur une nouvelle ligne, est ce qui leur permet de terminer le mot de passe.
SiegeX

Lors des tests sur FreeBSD avec bash 3.x, je trouve que ce n'est pas le cas. Tester sur Linux avec 3.1.17 donne vos résultats. Je n'ai pas de boîte BSD à portée de main pour le moment, mais je vais essayer de le confirmer demain, juste pour ma propre curiosité.
sorpigal

@Sorpigal: intéressant, laissez-moi savoir ce que vous découvrez. Je suis tout au sujet de la portabilité
SiegeX

2
J'ai compris. Mon test FreeBSD était basé sur le code copié et collé à partir de votre première édition erronée du message de lesmana, qui contient une différence importante: vous aviez passé readun fichier -d ''. Quand je l'ai réessayé plus tard sous Linux, j'ai utilisé la version republiée. Si j'essaie d'omettre, -d ''bien sûr, cela fonctionne de manière identique sur FreeBSD! Je suis en fait assez soulagé qu'il n'y ait pas de mystérieuse magie de plate-forme à l'œuvre ici.
sorpigal

17

pour une solution qui fonctionne sans bash ou certaines fonctionnalités que readvous pouvez utiliser sttypour désactiver l'écho

stty_orig=$(stty -g)
stty -echo
read password
stty $stty_orig

9

Voici une variante de l'excellente *solution d' impression de @ SiegeX bash avec prise en charge de l'espace arrière ajouté; cela permet à l'utilisateur de corriger son entrée avec la backspaceclé ( deleteclé sur un Mac) , comme cela est généralement pris en charge par les invites de mot de passe:

#!/usr/bin/env bash

password=''
while IFS= read -r -s -n1 char; do
  [[ -z $char ]] && { printf '\n'; break; } # ENTER pressed; output \n and break.
  if [[ $char == $'\x7f' ]]; then # backspace was pressed
      # Remove last char from output variable.
      [[ -n $password ]] && password=${password%?}
      # Erase '*' to the left.
      printf '\b \b' 
  else
    # Add typed char to output variable.
    password+=$char
    # Print '*' in its stead.
    printf '*'
  fi
done

Remarque:

  • Quant à savoir pourquoi appuyer sur le retour arrière enregistre le code de caractère 0x7f: "Dans les systèmes modernes, la touche de retour arrière est souvent mappée au caractère de suppression (0x7f en ASCII ou Unicode)" https://en.wikipedia.org/wiki/Backspace
  • \b \best nécessaire pour donner l'apparence de la suppression du caractère à gauche; juste utiliser \bdéplace le curseur vers la gauche, mais laisse le caractère intact ( retour arrière non destructif ). En imprimant un espace et en reculant à nouveau, le caractère semble avoir été effacé (merci, Le caractère d'échappement "retour arrière" '\ b' en C, comportement inattendu? ).

Dans un shell POSIX uniquement (par exemple, shsur Debian et Ubuntu, où shest dash), utilisez l' stty -echoapproche (qui est sous-optimale, car elle n'imprime rien ), car la fonction readintégrée ne supportera pas les options -set -n.


Merci, @Dylan. Je viens de réaliser que le code permettant de supprimer le dernier caractère du mot de passe saisi jusqu'à présent peut être simplifié - voir mise à jour.
mklement0

3

Un peu différent de (mais surtout comme) la réponse de @ lesmana

stty -echo
read password
stty echo

simplement: cacher l'écho faites vos trucs montrer l'écho


Pouvez-vous expliquer pourquoi c'est mieux que la réponse de @ lesmana ? Je vois que c'est plus simple avec moins de frais généraux pour un autre sttyappel, et une variable de moins sur la pile - ne supprimant que l'écho et ne restaurant que l'écho. Y a-t-il un moyen possible que cela puisse perturber d'autres sttyparamètres? Lesmana's préserve tous les paramètres.
Jeff Puckett

2

Voici une variante de la réponse de @ SiegeX qui fonctionne avec le shell Bourne traditionnel (qui ne prend pas en charge les +=affectations).

password=''
while IFS= read -r -s -n1 pass; do
  if [ -z "$pass" ]; then
     echo
     break
  else
     printf '*'
     password="$password$pass"
  fi
done

Un shell Bourne traditionnel (ou un shell compatible POSIX) ne reconnaîtrait pas non plus [[ ... ]], et son readintégré n'aurait pas non plus les options -set -n. Votre code ne fonctionnera donc pas dans dash, par exemple. (Il fonctionnera sur les plates-formes où shest en fait bash, comme sur OSX, où bashlorsqu'il est invoqué comme shmodifie simplement quelques options par défaut tout en prenant en charge la plupart des bashismes.)
mklement0

2
Merci pour vos commentaires, [je suis passé au single, mais je ne peux évidemment pas faire grand chose si vous readne disposez pas de ces options.
tripleee

2

J'aime toujours utiliser les caractères d'échappement Ansi:

echo -e "Enter your password: \x1B[8m"
echo -e "\x1B[0m"

8mrend le texte invisible et 0mréinitialise le texte à «normal». Le -e permet à Ansi de s'échapper.

La seule mise en garde est que vous pouvez toujours copier et coller le texte qui s'y trouve, vous ne devriez donc probablement pas l'utiliser si vous voulez vraiment la sécurité.

Il permet simplement aux gens de ne pas consulter vos mots de passe lorsque vous les saisissez. Ne laissez pas votre ordinateur allumé par la suite. :)


REMARQUE:

Ce qui précède est indépendant de la plate-forme tant qu'il prend en charge les séquences d'échappement Ansi.

Cependant, pour une autre solution Unix, vous pourriez simplement dire readde ne pas faire écho aux caractères ...

printf "password: "
let pass $(read -s)
printf "\nhey everyone, the password the user just entered is $pass\n"

1

Obtenez votre nom d'utilisateur et votre mot de passe

Rendez-le plus clair à lire, mais placez-le dans une meilleure position sur l'écran

#!/bin/bash
clear
echo 
echo 
echo
counter=0
unset username
prompt="  Enter Username:"
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]; then
        break
    elif [ $char == $'\x08' ] && [ $counter -gt 0 ]; then
        prompt=$'\b \b'
        username="${username%?}"
        counter=$((counter-1))
    elif [ $char == $'\x08' ] && [ $counter -lt 1 ]; then
        prompt=''
        continue
    else
        counter=$((counter+1))
        prompt="$char"
        username+="$char"
    fi
done
echo
unset password
prompt="  Enter Password:"
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]; then
        break
    elif [ $char == $'\x08' ] && [ $counter -gt 0 ]; then
        prompt=$'\b \b'
        password="${password%?}"
        counter=$((counter-1))
    elif [ $char == $'\x08' ] && [ $counter -lt 1 ]; then
        echo
        prompt="  Enter Password:"
        continue
    else
        counter=$((counter+1))
        prompt='*'
        password+="$char"
    fi
done
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.