Como passar variáveis com segurança a scripts ativados pela raiz?

13

Esta questão é totalmente geral e não apenas aplicável à minha situação, mas ... Eu tenho um pequeno appliance busybox onde eu quero que um usuário não-root seja capaz de executar um script particular com privilégios de root. Por exemplo, algo como este pequeno script para habilitar o DHCP, onde a única variável ( $1 ) a ser enviada no cmdline (!!) é o nome do host a ser enviado:

#!/bin/bash
udhcpc -b -i eth0 -h $1

executar udhcpc assim requer acesso root, então para isso eu planejo modificar /etc/sudoers para conter esta linha:

joe ALL = NOPASSWD: /path/to/enable_dhcp.sh

que deve permitir que "joe" execute facilmente esse script com privilégios de root simplesmente executando:

sudo /path/to/enable_dhcp.sh

e não ser perguntado por uma senha (que é o que eu quero, já que eu quero que o joe possa fazer o script disso).

Agora, eu sei (ou pelo menos acho que sim) que usar $1 em um script que pode ser facilmente executado com privilégios de root é uma idéia HORRÍVEL, já que você pode injetar o que quiser para isso.

Então ... qual é a melhor maneira de lidar com isso? Como faço para deixar o joe fazer o que eu quero com privilégios de root, permitir que ele passe uma variável (ou efetivamente faça isso com uma variável de ambiente), enquanto não estou aberto a ataques de injeção?

    
por Russ 29.07.2011 / 01:42

2 respostas

14

A execução de scripts de shell em sudo é segura , desde que sudo esteja configurado para redefinir o ambiente . Por outro lado, se sudo não reconfigurar o ambiente, a execução de um script de shell não será segura, mesmo que seu script não use seus parâmetros (consulte Permitir setuid em scripts de shell ). Verifique se você tem Defaults env_reset em /etc/sudoers ou se essa opção é o padrão em tempo de compilação ( sudo sudo -V | grep env deve incluir Reset the environment to a default set of variables ).

Não há perigo particular em usar os parâmetros de script. $1 é uma string, tudo que você precisa para ter certeza é que você está usando como uma string. (Por exemplo, não faça eval "$1" .) Obviamente, é especialmente importante aqui não fazer suposições sobre o conteúdo da variável, e para coloca aspas duplas em torno de todas as substituições de variáveis (ou seja, escreve "$1" , não $1 ). Observe que colocar aspas duplas em torno de substituições de variáveis não é específico para scripts executados com privilégios, é algo que você deve fazer o tempo todo.

Você pode querer validar mais o parâmetro, dependendo do que udhcpc faz com algo que não se parece com um nome de host. Por exemplo, isso executará uma primeira verificação sintática:

#!/bin/sh
case "$1" in
  *[!:-.0-9A-Za-z]*|-*) echo 1>&2 "Badly formed host name!"; exit 3;;
esac
udhcpc -b -i eth0 -h "$1"
    
por 29.07.2011 / 02:46
5

Você deve combinar a entrada passada contra um bom padrão conhecido.

Por exemplo, parece que um endereço IP pode ser uma entrada válida para você. Então você poderia usar algo assim:

if [[ "$1" =~ ^[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9]$ ]]
then
  udhcpc -b -i eth0 -h "$1"
else
  echo "Don't mess with me pork chop."
fi

Note que o regexp não foi testado, você é responsável por garantir que seu regexp não permita nada perigoso.

    
por 29.07.2011 / 02:37