Как безопасно передавать переменные в сценарии с поддержкой root?

13

Этот вопрос носит общий характер и применим не только к моей ситуации, но ... У меня есть небольшое устройство busybox, где я хочу, чтобы пользователь без полномочий root мог выполнять определенный сценарий с привилегиями пользователя root. Например, что-то вроде этого небольшого скрипта для включения DHCP, где единственная переменная ( $1) для отправки в cmdline (!!) - это то, какое имя хоста отправлять:

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

для запуска udhcpc, подобного этому, требуется root-доступ, поэтому для этого я планирую /etc/sudoersвнести изменения, содержащие следующую строку:

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

что должно позволить "joe" легко запускать этот скрипт с привилегиями root, просто запустив:

sudo /path/to/enable_dhcp.sh

и не запрашивать пароль (это то, что я хочу, так как я хочу, чтобы Джо мог написать это).

Теперь ... Я знаю (или, по крайней мере, думаю, что знаю), что использование $1в скрипте, который легко может быть запущен с привилегиями root, является УЖАСНОЙ идеей, поскольку вы можете внедрить в нее все, что захотите.

Итак ... каков наилучший способ справиться с этим? Как я могу позволить joe делать то, что я хочу, с правами суперпользователя, разрешать ему передавать переменную (или эффективно делать это, как с переменной окружения), не будучи широко открытыми для атак с использованием инъекций?

Russ
источник

Ответы:

14

Запуск сценариев оболочки под sudoбезопасным, если sudoон настроен для сброса среды . И наоборот, если sudoсреда не сбрасывается, тогда запуск сценария оболочки небезопасен, даже если ваш сценарий не использует его параметры (см. Разрешить setuid для сценариев оболочки ). Убедитесь , что у вас есть Defaults env_resetв /etc/sudoersили что этот параметр во время компиляции по умолчанию ( sudo sudo -V | grep envдолжен включать Reset the environment to a default set of variables).

Особой опасности при использовании параметров скрипта нет. $1это строка, все что вам нужно, это убедиться, что вы используете ее как строку. (Например, не делайте eval "$1".) Очевидно, что здесь особенно важно не делать предположений относительно содержимого переменной, а ставить двойные кавычки вокруг всех подстановок переменных (т.е. писать "$1", а не $1). Обратите внимание, что двойные кавычки вокруг подстановок переменных не являются специфичными для скриптов, работающих с привилегиями, это то, что вы должны делать постоянно.

Возможно, вы захотите проверить параметр дальше, в зависимости от того, что udhcpcделает с чем-то, что не похоже на имя хоста. Например, это выполнит первую синтаксическую проверку:

#!/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"
Жиль "ТАК - прекрати быть злым"
источник
Другие факторы, которые следует учитывать, могут повлиять на поведение этой команды: текущий рабочий каталог и то, на что указывают stdin, stdout, stderr, обработчики сигналов и ulimits. Например, разрешая дампы ядра (после <kbd> Ctrl - \ </ kbd>), вы можете разрешить пользователю мусорить / запускать / блокировать, что в моей системе является tmpfs с очень ограниченным размером и может разрешить DoS.
Стефан Шазелас
5

Вы должны сопоставить переданный ввод с известным хорошим шаблоном.

Например, похоже, что IP-адрес может быть правильным вводом для вас. Таким образом, вы можете использовать что-то вроде этого:

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

Обратите внимание, что регулярное выражение не было проверено, вы несете ответственность за то, чтобы ваше регулярное выражение не позволяло ничего опасного.

bahamat
источник