Eco con ofuscación

15

Necesito imprimir algunas variables en la pantalla, pero necesito ofuscar preferentemente los primeros caracteres y me preguntaba si había un comando echo en bash que pudiera ofuscar los primeros caracteres de un valor secreto al imprimirlo en el terminal:

echo 'secretvalue'
********lue
Jerjes
fuente

Respuestas:

11

Las otras respuestas enmascaran una cantidad fija de caracteres desde el principio, con el sufijo de texto plano que varía en longitud. Una alternativa sería dejar una cantidad fija de caracteres en texto sin formato y variar la longitud de la parte enmascarada. No sé cuál es más útil, pero aquí está la otra opción:

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

Esto imprime **cdey *********jkl.


Si lo desea, también puede modificar ncadenas cortas para asegurarse de que se enmascara la mayoría de las cadenas. Por ejemplo, esto aseguraría que al menos tres caracteres estén enmascarados incluso para cadenas cortas. (entonces abcde-> ***de, y 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
fuente
13

Una opción sería obligarse a usar una función en lugar de echo, como:

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

Entonces podría llamar obfuprint 'secretvalue'y recibir ********lue(con una nueva línea final). La función utiliza la expansión de parámetros para buscar los primeros ocho caracteres del valor pasado y los reemplaza con ocho asteriscos. Si el valor entrante es más corto que ocho caracteres, todos se reemplazan con asteriscos. ¡Gracias a ilkkachu por señalar mi suposición inicial de ocho o más entradas de caracteres!


Inspirado por la respuesta de enmascaramiento flexible de ilkkachu , pensé que sería interesante agregar una variación que enmascara al azar algún porcentaje de la cadena:

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
}

Esto se basa en la $RANDOMvariable especial de bash ; simplemente recorre cada carácter de la entrada y decide si enmascarar ese carácter o imprimirlo. Salida de muestra:

$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
Jeff Schaller
fuente
Para ser sincero, no me gusta el enmascaramiento aleatorio. Un surfista de hombros determinado eventualmente obtendrá mis secretos fingiendo que le gusta conversar conmigo.
emory
¡Ciertamente, la visualización de información confidencial debe hacerse con cuidado! Presente el enmascaramiento aleatorio como una alternativa al enmascaramiento de prefijo fijo y al enmascaramiento de prefijo variable.
Jeff Schaller
44
Tampoco soy un fanático del enmascaramiento de prefijo fijo o prefijo variable, pero con ellos existe un "núcleo" de mi secreto que sigue siendo secreto. Con el enmascaramiento aleatorio, no hay "núcleo". Finalmente, todo se revelará a los pacientes lo suficiente.
emory
7

Podrías intentarlo sed. Por ejemplo, para reemplazar los primeros 8 caracteres de una cadena con asteriscos, puede canalizar el sed 's/^......../********/'comando, por ejemplo:

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

También puede definir una función que haga esto:

obsecho () { echo "$1" | sed 's/^......../*********/'; }
igal
fuente
2
Yo sugeriría printfsobreecho lo que no está sujeto a la interpretación de los datos, tales como \ro\n
Jeff Schaller
@JeffSchaller Esta es una de las razones por las que publico en SE. Buen punto. Gracias por la respuesta.
igal
¡Es una de las muchas cosas que he aprendido en mi tiempo aquí también! ¡Feliz de pasarlo!
Jeff Schaller
1
No es necesario usar una tubería cuando se puede usar una herejía:sed 's/^......../********/' <<< 'secretvalue'
wjandrea
@roaima En realidad es un archivo regular temporal. Puedes verlo si lo haces bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.
JoL
7

Una zshvariante que enmascara tres cuartos del texto:

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

Ejemplo:

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

Para enmascarar los primeros 8 caracteres:

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

Para enmascarar todos menos los últimos 3 caracteres:

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

Para enmascarar un número aleatorio de caracteres:

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

Otra opción en Bash, si no te importa una simple eval, puedes hacerlo con un 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}"

Pero ten cuidado:

  • arregle lo anterior como necesite cuando ${#password}sea ​​menor que${chars_to_show}
  • evalpuede ser muy peligroso con entradas no confiables: aquí puede considerarse seguro porque su entrada proviene solo de fuentes seguras, es decir, la longitud ${password}y el valor de${chars_to_show}
LL3
fuente
0

Aquí hay algunos scripts de Toy Bash para jugar que muestran cómo combinar la búsqueda de expresiones regulares con la sustitución de cadenas.

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

Para llevar clave

  • [a-z 0-9]es totalmente válido y útil, como un <search>dentro ${_var_name//<search>/<replace>}de Bash
  • ^, dentro de este contexto, es al revés o notpara búsquedas tipo regex
  • Los empotrados son generalmente más rápidos y a menudo son más concisos, especialmente cuando se cortan las tuberías innecesarias.

Si bien entiendo que printfes mejor en casi todos los casos de uso, el código anterior usa echopara no confundir demasiado lo que está sucediendo.

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
fuente