O cenário:
Em um script bash, eu tenho que verificar se uma senha fornecida por um usuário é uma senha de usuário válida.
Ou seja, suponha que eu tenho um usuário A com senha PA .. No script, pedi ao usuário A para digitar sua senha. Então, como verificar se a sequência digitada é realmente a sua senha? ...
expect
pelo stackoverflow.com/a/1503831/320594 .Respostas:
Como você deseja fazer isso em um script de shell, algumas contribuições em Como verificar a senha no Linux? (no Unix.SE , sugerido pela AB ) são especialmente relevantes:
/etc/shadow
fornece parte da solução.mkpasswd
comando presente no Debian (e Ubuntu).Para verificar manualmente se uma sequência é realmente a senha de algum usuário, você deve fazer o hash com o mesmo algoritmo de hash que na entrada de sombra do usuário, com o mesmo sal que na entrada de sombra do usuário. Em seguida, pode ser comparado com o hash da senha armazenado lá.
Escrevi um script de trabalho completo demonstrando como fazer isso.
chkpass
, poderá executar e ele lerá uma linha da entrada padrão e verificará se é a senha.chkpass user
user
mkpasswd
utilitário do qual esse script depende.Notas de segurança
Pode não ser a abordagem correta.
Se uma abordagem como essa deve ou não ser considerada segura e apropriada depende de detalhes sobre o seu caso de uso que você não forneceu (até o momento em que este artigo foi escrito).
Não foi auditado.
Embora eu tenha tentado tomar cuidado ao escrever esse script, ele não foi auditado corretamente para detectar vulnerabilidades de segurança . Pretende-se como uma demonstração e seria um software "alfa" se lançado como parte de um projeto. Além disso...
Outro usuário que está "assistindo" pode descobrir o sal do usuário .
Devido a limitações na
mkpasswd
aceitação de dados salt, este script contém uma falha de segurança conhecida , que você pode ou não considerar aceitável, dependendo do caso de uso. Por padrão, os usuários do Ubuntu e da maioria dos outros sistemas GNU / Linux podem visualizar informações sobre processos executados por outros usuários (incluindo raiz), incluindo seus argumentos de linha de comando. Nem a entrada do usuário nem o hash da senha armazenada são passados como um argumento da linha de comandos para qualquer utilitário externo. Mas o salt , extraído doshadow
banco de dados, é fornecido como um argumento de linha de comandomkpasswd
, pois essa é a única maneira pela qual o utilitário aceita um salt como entrada.E se
www-data
) execute seu código ou/proc
)é capaz de verificar os argumentos da linha de comandos
mkpasswd
conforme são executados por esse script, e eles podem obter uma cópia do sal do usuário noshadow
banco de dados. Talvez eles precisem adivinhar quando esse comando é executado, mas isso às vezes é possível.Um atacante com seu sal não é tão ruim quanto um atacante com seu sal e hash , mas não é o ideal. O sal não fornece informações suficientes para alguém descobrir sua senha. Mas permite que alguém gere tabelas arco-íris ou hashes de dicionário pré-calculados específicos para esse usuário nesse sistema. Inicialmente, isso é inútil, mas se sua segurança for comprometida posteriormente e o hash completo for obtido, poderá ser quebrado mais rapidamente para obter a senha do usuário antes que eles possam alterá-la.
Portanto, essa falha de segurança é um fator exacerbador em um cenário de ataque mais complexo, em vez de uma vulnerabilidade totalmente explorável. E você pode considerar a situação acima exagerada. Mas eu estou relutante em recomendar qualquer método para geral, o uso do mundo real que vazamentos de quaisquer dados não-públicos de
/etc/shadow
que um usuário não-raiz.Você pode evitar esse problema completamente:
Cuidado ao chamar esse script.
Se você permitir que um usuário não confiável execute esse script como root ou execute qualquer processo como root que chame esse script, tenha cuidado . Ao alterar o ambiente, eles podem fazer com que esse script - ou qualquer script que seja executado como root - faça qualquer coisa . A menos que você possa impedir que isso ocorra, você não deve permitir aos usuários privilégios elevados para executar scripts de shell.
Veja 10.4. Linguagens de script de shell (derivadas sh e csh) no HOWTO de programação segura de David A. Wheeler para Linux e UNIX para obter mais informações sobre isso. Embora sua apresentação se concentre em scripts setuid, outros mecanismos podem ser vítimas de alguns dos mesmos problemas se não higienizarem corretamente o ambiente.
Outras notas
Ele suporta hashes de leitura
shadow
apenas do banco de dados.As senhas devem estar sombreadas para que esse script funcione (ou seja, seus hashes devem estar em um
/etc/shadow
arquivo separado no qual somente o root possa ler, não no/etc/passwd
).Este sempre deve ser o caso no Ubuntu. Em qualquer caso, se necessário, o script pode ser estendido trivialmente para ler os hashes de senha
passwd
e tambémshadow
.Lembre-
IFS
se de modificar este script.Defino
IFS=$
no início, pois os três dados no campo hash de uma entrada de sombra são separados por$
.$
, razão pela qual o tipo de hash e o sal são"${ent[1]}"
e, em"${ent[2]}"
vez de"${ent[0]}"
e"${ent[1]}"
, respectivamente.Os únicos lugares neste script onde
$IFS
determinam como o shell divide ou combina palavras sãoquando esses dados são divididos em uma matriz, inicializando-os a partir da
$(
)
substituição de comando não citado em:quando a matriz é reconstituída em uma sequência para comparar com o campo completo de
shadow
, a"${ent[*]}"
expressão em:Se você modificar o script e fazê-lo executar a divisão de palavras (ou junção de palavras) em outras situações, será necessário definir
IFS
valores diferentes para comandos diferentes ou partes diferentes do script.Se você não se lembrar disso e assumir que
$IFS
está definido como o espaço em branco habitual ($' \t\n'
), você pode acabar fazendo seu script se comportar de maneiras bem estranhas.fonte
Você pode abusar
sudo
disso.sudo
tem a-l
opção, para testar os privilégios sudo que o usuário possui e-S
para ler a senha do stdin. No entanto, não importa qual nível de privilégio o usuário tenha, se autenticado com êxito,sudo
retornará com o status de saída 0. Portanto, você pode usar qualquer outro status de saída como indicação de que a autenticação não funcionou (supondo quesudo
ele não tenha problemas, como erros de permissão ousudoers
configuração inválida ).Algo como:
Este script depende bastante da
sudoers
configuração. Eu assumi a configuração padrão. Coisas que podem causar falhas:targetpw
ourunaspw
está definidolistpw
énever
Outros problemas incluem (obrigado Eliah):
/var/log/auth.log
sudo
deve ser executado como o usuário para o qual você está se autenticando. A menos que você tenhasudo
privilégios para poder executarsudo -u foo sudo -lS
, isso significa que você precisará executar o script como usuário de destino.Agora, a razão pela qual usei os documentos aqui é dificultar a escuta. Uma variável usada como parte da linha de comando é mais facilmente revelada usando
top
oups
ou outras ferramentas para inspecionar processos.fonte
sudo
configurações incomuns (como você diz) e/var/log/auth.log
com registros de cada tentativa, isso é rápido, simples e usa um utilitário existente, em vez de reinventar a roda (por assim dizer). Sugiro definirIFS=
pararead
, para evitar falsos sucessos na entrada do usuário preenchida com espaço em branco e senhas não preenchidas, bem como falhas falsas na entrada do usuário preenchida com espaço em branco e senhas preenchidas. (Minha solução teve um bug semelhante.) Você também pode explicar como deve ser executado como o usuário cuja senha está sendo verificada.sudo -l
faz com que uma entrada seja gravada com "COMMAND=list
". Btw (não relacionado), embora não seja objetivamente melhor fazê-lo, o uso de uma string here no lugar de um documento here atinge o mesmo objetivo de segurança e é mais compacto. Como o script já usa os bashismsread -s
e&>
, usingif sudo -lS &>/dev/null <<<"$PASSWD"; then
não é menos portátil. Não estou sugerindo que você mude o que tem (tudo bem). Em vez disso, mencionei para que os leitores saibam que também têm essa opção.sudo -l
algo desativado - talvez estivesse relatando quando um usuário tenta executar um comando que ele não tem permissão.Outro método (provavelmente mais interessante por seu conteúdo teórico do que por suas aplicações práticas).
As senhas do usuário são armazenadas em
/etc/shadow
.As senhas armazenadas aqui são criptografadas, nas últimas versões do Ubuntu usando
SHA-512
.Especificamente, após a criação da senha, a senha em texto não criptografado é salgada e criptografada
SHA-512
.Uma solução seria saltar / criptografar a senha fornecida e compará-la com a senha do usuário criptografado armazenada na
/etc/shadow
entrada do usuário .Para fornecer uma rápida descrição de como as senhas são armazenadas em cada
/etc/shadow
entrada do usuário , veja uma amostra de/etc/shadow
entrada para um usuáriofoo
com senhabar
:foo
: nome do usuário6
: tipo de criptografia da senhalWS1oJnmDlaXrx1F
: sal de criptografia da senhah4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/
:SHA-512
senha salgada / criptografadaPara corresponder à senha fornecida
bar
para o usuáriofoo
, a primeira coisa a fazer é obter o sal:Em seguida, deve-se obter a senha completa salgada / criptografada:
Em seguida, a senha fornecida pode ser salgada / criptografada e comparada com a senha do usuário salgada / criptografada armazenada em
/etc/shadow
:Eles combinam! Tudo colocado em um
bash
script:Resultado:
fonte
sudo getent shadow
>>sudo grep ...
. Caso contrário, legal. Isso é o que eu pensava originalmente, então fiquei com preguiça.getent
+grep
+cut
>grep
+cut
getent
pode fazer a busca por você. Tomei a liberdade de editar.mkpasswd
gerar um hash a partir da entrada do usuário e do sal existente (e incluía recursos e diagnósticos adicionais), você codificou um programa simples em Python implementandomkpasswd
a funcionalidade mais importante e usou isso. Eu recomendo que você definaIFS=
ao ler a entrada de senha e cite${password}
com"
, para que tentativas de senha com espaço em branco não quebrem o script.