Gerando uma senha aleatória; por que isso não é portátil?

21

Quero gerar uma senha aleatória e faço assim:

</dev/urandom tr -dc [:print:] | head -c 64

No meu laptop, que executa o Ubuntu, isso produz apenas caracteres imprimíveis, conforme pretendido. Mas quando ssh no servidor da minha escola, que executa o Red Hat Enterprise Linux, e o executo lá, recebo resultados como o 3!ri�b�GrӴ��1�H�<�oM����&�nMC[�Pb�|L%MP�����9��fL2q���IFmsd|l�Kque não funcionam. O que pode estar errado aqui?

Taymon
fonte

Respostas:

34

É o seu problema de localidade e tr .

Atualmente, o GNU tr suporta totalmente apenas caracteres de byte único. Portanto, em locais usando codificações multibyte, a saída pode ser estranha:

$ </dev/urandom LC_ALL=vi_VN.tcvn tr -dc '[:print:]' | head -c 64
`�pv���Z����c�ox"�O���%�YR��F�>��췔��ovȪ������^,<H ���>

O shell imprimirá caracteres de vários bytes corretamente, mas o GNU trremoverá os bytes que julgar imprimíveis.

Se você deseja que ele seja estável, você deve definir o código do idioma:

$ </dev/urandom LC_ALL=C tr -dc '[:print:]' | head -c 64
RSmuiFH+537z+iY4ySz`{Pv6mJg::RB;/-2^{QnKkImpGuMSq92D(6N8QF?Y9Co@
cuonglm
fonte
14
+1 porque isso me fez perceber (usando shells no Unix / Linux por apenas 30 anos), que o redirecionamento stdin / stdout / stderr não precisa ser posicionado após o comando ao qual se aplica.
Anthon
Apenas um comentário, se algum código de idioma estranho estiver definido, o shell ainda não poderá imprimir os caracteres corretamente, mesmo que não sejam ascii? Pelo menos um shell competente (excluindo o xterm, é claro)?
Orion
2
@orion: o shell imprimirá os caracteres corretamente. Nesse caso, isso é um problema. Ele removeu os bytes que considera imprimíveis, torna o resultado estranho.
precisa saber é
@orion Um fluxo uniformemente aleatório de bytes não será, em geral, um fluxo uniformemente aleatório de codificações de caracteres UTF-8 bem formadas .
Zwol 18/06/2015
Além disso, a menos que você o que os espaços em sua senha, você deve usar :graph:em vez de :print::</dev/urandom LC_ALL=C tr -dc '[:graph:]' | head -c 64
edan
11

Considere em vez disso

$ dd if=/dev/urandom bs=48 count=1 status=none | base64
imW/X60Sk9TQzl+mdS5PL7sfMy9k/qFBWWkzZjbYJttREsYpzIguWr/uRIhyisR7

Isso tem duas vantagens:

  • Você lê apenas 48 bytes do dispositivo aleatório, não ~ 8KB; se outros processos no mesmo host precisarem de números aleatórios, 8 KB esgotados de uma só vez podem ser um problema sério. (Sim, sem dúvida, ninguém deve estar usando o bloqueio de dispositivo aleatório, mas as pessoas fazem .)

  • A saída de base64quase não contém caracteres com significados especiais. (Para nenhum, a aderência | tr +/ -_sobre a extremidade, e (como no exemplo) certificar-se o número de bytes de entrada a base64é um múltiplo de 3)

Uma senha gerada dessa maneira possui exatamente 384 bits de entropia, que é um pouco menor do que o que você estava fazendo (log 2 96 64 × 421.4), mas é mais do que suficiente para a maioria dos propósitos (256 bits de entropia está em segurança "ainda adivinhando quando o A Sun queima o território ", exceto as chaves RSA, AFAIK).

zwol
fonte
3

Outras pessoas já apontaram que locale determina o que [:print:]significa. No entanto, nem todos os caracteres imprimíveis são adequados para senhas (nem mesmo em ascii). Você realmente não quer espaços, tabulações e # $% ^? na sua senha - não é apenas difícil de lembrar, também é potencialmente perigoso para o sistema de autenticação subjacente, pode ser impossível entrar em um campo de entrada e assim por diante. Nesse caso, você deve apenas selecionar manualmente caracteres "sãos":

LC_ALL=C </dev/urandom tr -dc '[:alnum:]_' | head -c 64

ou simplesmente

</dev/urandom tr -dc 'A-Za-z0-9_' | head -c 64

Ou melhor ainda, use base64como sugerido em outras respostas.

orion
fonte
A senha em questão nunca será inserida por seres humanos (se fosse usar o Diceware) e tenho certeza de que o sistema subjacente pode lidar com caracteres especiais sem problemas. Obrigado mesmo assim.
Taymon 02/02
4
O que você diz está totalmente errado. Forçar os usuários a usar apenas letras, dígitos e sublinhado ASCII reduz consideravelmente o tamanho do alfabeto, facilitando a quebra de senhas dos invasores. Um sistema de autenticação que nem consegue lidar ?ou ^é ruim demais para ser levado a sério.
Bakuriu 02/02
2
Se o seu sistema de autenticação ou os campos de entrada estiverem bloqueados com símbolos ASCII comuns ... então você está fazendo algo errado e não deve ser confiável com minhas informações privadas. Não há absolutamente nenhuma razão para não aceitar todos os tipos de caracteres (incluindo espaços) em suas senhas.
Nzifnab
2
Parece que esse não é o caso aqui, mas quando se trata de informações humanas, é muito mais fácil lembrar de uma senha alfanumérica longa que possui um significado único para o proprietário do que uma mistura mais curta de símbolos. Há também a questão de inserir esses caracteres em vários teclados (nem todo mundo tem ^ no primeiro nível e a maioria das pessoas nem sabe onde ou o que é um backtick), as caixas de entrada quase certamente não conseguem lidar com o caractere de tabulação e um Um número surpreendente de formulários da web ainda estão suscetíveis a erros de validação, injeção de sql ou até sensibilidade a casos incertos.
orion
1
Apenas uma observação: na [:print:]classe C locale não inclui guias. É apenas [:alnum:]+ [:punct:]+ espaço (espaço único, não [:space:] ).
jimmij
2

Sobre o quê

tr -dc [:print:] < /dev/urandom | head -c 64 | strings

strings devem imprimir a saída do urandom em um formato imprimível

Blindstealer
fonte
Isso dá #-bash: /dev/urandom: Permission denied
Anthon
não esqueceu o gato levando
Blindstealer
2

Não sei se existe algum motivo para você /dev/randomgerar a senha, mas eu recomendaria o uso do pwgen para aliviar sua dor.

$ pwgen -s 10 1

Onde 10 é o comprimento da senha.

http://man.cx/pwgen

Daniel
fonte
1
#Chars allowed in password (I don't like l,o,O, etc):
P="0123456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz"

#Or such:
#P="a-zA-Z0-9"

head -c 8 < /dev/urandom | tr '\000-\377' "$P$P$P$P$P"
echo

Este método IMHO é mais inteligente quando consumir dados de / dev / urandom A string colada como $ P $ P $ P ... deve ter pelo menos 256 caracteres.

Alexander Kelner
fonte