Eco com ofuscação

15

Preciso imprimir algumas variáveis ​​na tela, mas preferencialmente ofuscar os primeiros caracteres e queria saber se havia um comando echo no bash que pode ofuscar os primeiros caracteres de um valor secreto enquanto o imprime no terminal:

echo 'secretvalue'
********lue
Xerxes
fonte

Respostas:

11

As outras respostas ocultam uma quantidade fixa de caracteres desde o início, com o sufixo de texto sem formatação variando em tamanho. Uma alternativa seria deixar uma quantidade fixa de caracteres em texto simples e variar o comprimento da parte mascarada. Não sei qual é mais útil, mas aqui está a outra opção:

#!/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

Isso imprime **cdee *********jkl.


Se desejar, você também pode modificar nas strings curtas para garantir que a maioria das strings seja mascarada. Por exemplo, isso garantiria que pelo menos três caracteres sejam mascarados, mesmo para seqüências curtas. (então abcde-> ***dee 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
fonte
13

Uma opção seria forçar-se a usar uma função em vez de echo, como:

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

Em seguida, você pode ligar obfuprint 'secretvalue'e receber ********lue(com uma nova linha à direita). A função usa a expansão de parâmetro para procurar os oito primeiros caracteres do valor passado e os substitui por oito asteriscos. Se o valor recebido for menor que oito caracteres, todos serão substituídos por asteriscos. Obrigado a ilkkachu por apontar minha suposição inicial de oito ou mais entradas de caracteres!


Inspirado pela resposta flexível de mascaramento do ilkkachu , achei interessante adicionar uma variação que mascara aleatoriamente uma porcentagem da string:

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
}

Isso depende da $RANDOMvariável especial do bash ; ele simplesmente percorre cada caractere da entrada e decide se deve mascará-lo ou imprimi-lo. Saída de amostra:

$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
Jeff Schaller
fonte
Para ser franco, não gosto de máscaras aleatórias. Um determinado surfista do ombro acabará por descobrir meus segredos fingindo gostar de conversar comigo.
Emory
Certamente, a exibição de informações confidenciais deve ser feita com cuidado! Apresentei o mascaramento aleatório como uma alternativa ao mascaramento de prefixo fixo e ao prefixo variável.
Jeff Schaller
4
Também não sou fã de máscaras de prefixo fixo ou de prefixo variável, mas com elas existe um "núcleo" do meu segredo que permanece secreto. Com o mascaramento aleatório, não há "kernel". Eventualmente, tudo será revelado àqueles pacientes o suficiente.
Emory
7

Você pode tentar canalizar para sed. Por exemplo, para substituir os 8 primeiros caracteres de uma string por asteriscos, você pode canalizar para o sed 's/^......../********/'comando, por exemplo:

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

Você também pode definir uma função que faça isso:

obsecho () { echo "$1" | sed 's/^......../*********/'; }
igal
fonte
2
Eu sugeriria printfmais,echo para que você não esteja sujeito a interpretar dados como \rou\n
Jeff Schaller
@JeffSchaller Essa é uma das razões pelas quais eu posto no SE. Bom ponto. Obrigado pelo feedback.
igal 20/03/19
É uma das muitas coisas que aprendi no meu tempo aqui também! Feliz em passar adiante!
Jeff Schaller
1
Não é necessário usar um cano quando você pode usar um herestring:sed 's/^......../********/' <<< 'secretvalue'
wjandrea
@roaima Na verdade, é um arquivo regular temporário. Você pode ver se você faz bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.
21419 JoL
7

Uma zshvariante que mascara três quartos do texto:

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

Exemplo:

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

Para mascarar os 8 primeiros caracteres:

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

Para mascarar todos, exceto os últimos 3 caracteres:

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

Para mascarar um número aleatório de caracteres:

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

Outra opção no Bash, se você não se importa com um simples, evalpode fazê-lo com um par de 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}"

Mas tenha cuidado:

  • corrija o acima, conforme necessário, quando ${#password}for menor que${chars_to_show}
  • evalpode ser muito perigoso com entradas não confiáveis: aqui pode ser considerada segura porque sua entrada vem apenas de fontes seguras, ou seja, o comprimento ${password}e o valor de${chars_to_show}
LL3
fonte
0

Aqui estão alguns scripts Bash de brinquedo para brincar, que mostram como combinar pesquisa do tipo regex com substituição de string.

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

Principais tópicos

  • [a-z 0-9]é totalmente válido e útil, como <search>dentro ${_var_name//<search>/<replace>}de Bash
  • ^, nesse contexto, é o inverso ou notpara pesquisas do tipo regex
  • Os embutidos geralmente são mais rápidos e geralmente são mais concisos, especialmente quando cortam tubulações desnecessárias

Embora eu consiga que isso printfseja melhor em quase todos os casos de uso, o código acima usa echopara não confundir excessivamente o que está acontecendo.

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
fonte