Écho avec obscurcissement

15

J'ai besoin d'imprimer certaines variables à l'écran mais je dois de préférence brouiller les premiers caractères et je me demandais s'il y avait une commande echo dans bash qui peut brouiller les premiers caractères d'une valeur secrète lors de l'impression sur le terminal:

echo 'secretvalue'
********lue
Xerxès
la source

Réponses:

11

Les autres réponses masquent un nombre fixe de caractères dès le début, le suffixe en clair variant en longueur. Une alternative serait de laisser un nombre fixe de caractères en texte clair et de faire varier la longueur de la partie masquée. Je ne sais pas lequel est le plus utile, mais voici l'autre choix:

#!/bin/bash
mask() {
        local n=3                    # number of chars to leave
        local a="${1:0:${#1}-n}"     # take all but the last n chars
        local b="${1:${#1}-n}"       # take the final n chars 
        printf "%s%s\n" "${a//?/*}" "$b"   # substitute a with asterisks
}

mask abcde
mask abcdefghijkl

Cela imprime **cdeet *********jkl.


Si vous le souhaitez, vous pouvez également modifier nles chaînes courtes pour vous assurer que la majorité de la chaîne est masquée. Par exemple, cela garantirait qu'au moins trois caractères sont masqués, même pour les chaînes courtes. (donc abcde-> ***de, et abc-> ***):

mask() {
        local n=3
        [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
        local a="${1:0:${#1}-n}"
        local b="${1:${#1}-n}"
        printf "%s%s\n" "${a//?/*}" "$b"
}
ilkkachu
la source
13

Une option serait de vous forcer à utiliser une fonction au lieu de echo, comme:

obfuprint() {
  if [ "${#1}" -ge 8 ]
  then
    printf '%s\n' "${1/????????/********}"
  else
    printf '%s\n' "${1//?/*}"
  fi
}

Ensuite, vous pouvez appeler obfuprint 'secretvalue'et recevoir ********lue(avec une nouvelle ligne de fin). La fonction utilise l'expansion des paramètres pour rechercher les huit premiers caractères de la valeur transmise et les remplace par huit astérisques. Si la valeur entrante est inférieure à huit caractères, ils sont tous remplacés par des astérisques. Merci à ilkkachu d' avoir souligné mon hypothèse initiale de huit caractères ou plus!


Inspiré par la réponse de masquage flexible d' ilkkachu , j'ai pensé qu'il serait intéressant d'ajouter une variation qui masque aléatoirement un certain pourcentage de la chaîne:

obfuprintperc () {
  local perc=75  ## percent to obfuscate
  local i=0
  for((i=0; i < ${#1}; i++))
  do
    if [ $(( $RANDOM % 100 )) -lt "$perc" ]
    then
        printf '%s' '*'
    else
        printf '%s' "${1:i:1}"
    fi
  done
  echo
}

Cela dépend de la $RANDOMvariable spéciale de bash ; il parcourt simplement chaque caractère de l'entrée et décide de masquer ce caractère ou de l'imprimer. Exemple de sortie:

$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
Jeff Schaller
la source
Pour être franc, je n'aime pas le masquage aléatoire. Un surfeur d'épaule déterminé finira par obtenir mes secrets en faisant semblant d'aimer faire de petites conversations avec moi.
emory
Certes, l'affichage des informations sensibles doit être fait avec soin! J'ai présenté le masquage aléatoire comme une alternative au masquage à préfixe fixe et au masquage à préfixe variable.
Jeff Schaller
4
Je ne suis pas non plus un fan du masquage à préfixe fixe ou à préfixe variable, mais avec ceux-ci, il existe un "noyau" de mon secret qui reste secret. Avec le masquage aléatoire, il n'y a pas de "noyau". Finalement, tout sera suffisamment révélé à ces patients.
emory
7

Vous pouvez essayer de la tuyauterie sed. Par exemple, pour remplacer les 8 premiers caractères d'une chaîne par des astérisques, vous pouvez diriger vers la sed 's/^......../********/'commande, par exemple:

$ echo 'secretvalue' | sed 's/^......../********/'
********lue

Vous pouvez également définir une fonction qui fait ceci:

obsecho () { echo "$1" | sed 's/^......../*********/'; }
igal
la source
2
Je vous suggère de printfplusecho pour que vous n'êtes pas soumis à l' interprétation des données telles que \rou\n
Jeff Schaller
@JeffSchaller C'est l'une des raisons pour lesquelles je poste sur SE. Bon point. Merci pour les commentaires.
igal
C'est aussi l'une des nombreuses choses que j'ai apprises pendant mon séjour ici! Heureux de le transmettre!
Jeff Schaller
1
Pas besoin d'utiliser une pipe quand vous pouvez utiliser une herestring à la place:sed 's/^......../********/' <<< 'secretvalue'
wjandrea
@roaima Il s'agit en fait d'un fichier ordinaire temporaire. Vous pouvez le voir si vous le faites bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.
JoL
7

Une zshvariante qui masque les trois quarts du texte:

mask() printf '%s\n' ${(l:$#1::*:)1:$#1*3/4}

Exemple:

$ mask secretvalue
********lue
$ mask 12345678
******78
$ mask 1234
***4

Pour masquer les 8 premiers caractères:

mask() printf '%s\n' ${(l:$#1::*:)1:8}

Pour masquer tous les caractères sauf les 3 derniers:

mask() printf '%s\n' ${(l:$#1::*:)1: -3}

Pour masquer un nombre aléatoire de caractères:

mask() printf '%s\n' ${(l:$#1::*:)1: RANDOM%$#1}
Stéphane Chazelas
la source
2

Une autre option dans Bash, si cela ne vous dérange pas, evalvous pouvez le faire avec quelques printf:

# example data
password=secretvalue
chars_to_show=3

# the real thing
eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
printf '%s\n' "${password: -chars_to_show}"

Mais fais attention:

  • fixer ci - dessus que vous avez besoin quand ${#password}est inférieur à${chars_to_show}
  • evalpeut être très dangereux avec une entrée non fiable: ici, il peut être considéré comme sûr car son entrée ne provient que de sources sûres, c'est-à-dire la longueur ${password}et la valeur de${chars_to_show}
LL3
la source
0

Voici quelques scripts Bash jouets pour jouer avec qui montrent comment combiner une recherche de type regex avec une substitution de chaîne.

strip_str.sh

#!/usr/bin/env bash

_str="${1}"
_filter="${2:-'apl'}"
echo "${_str//[${_filter}]/}"
strip_str.sh 'apple-foo bar'
# -> e-foo br
strip_str.sh 'apple-foo bar' 'a'
# -> pple-foo br

privatize_str.sh

#!/usr/bin/env bash

_str="${1}"
_filter="${2:-'apl'}"
_replace="${3:-'*'}"
echo "${_str//[${_filter}]/${_replace}}"
privatize_str.sh 'apple-foo bar'
# -> ****e-foo b*r

restricted_str.sh

#!/usr/bin/env bash

_str="${1}"
_valid="${2:-'a-z'}"
_replace="${3:-''}"
echo "${_str//[^${_valid}]/${_replace}}"
restricted_str.sh 'apple-foo bar'
# -> applefoobar

Points clés à retenir

  • [a-z 0-9]est tout à fait valable, et à portée de main, comme au <search>sein ${_var_name//<search>/<replace>}de Bash
  • ^, dans ce contexte, est l'inverse ou notpour les recherches de type regex
  • Les éléments intégrés sont généralement plus rapides et souvent plus concis, en particulier lorsqu'ils coupent les tuyaux inutiles

Bien que ce printfsoit mieux dans presque tous les cas d'utilisation, le code ci-dessus utilise echopour ne pas trop confondre ce qui se passe.

obfuscate_str.sh

#!/usr/bin/env bash

_str="${1}"
_start="${2:-6}"
_header="$(for i in {1..${_start}}; do echo -n '*'; done)"
echo "${_header}${_str:${_start}}"
obfuscate_str.sh 'apple-foo bar' 3
# -> ***le-foo bar
S0AndS0
la source