У меня была такая же проблема. У меня есть 2 джейла, ssh и recidive. Тюрьма ssh прекрасно отправляла мне электронные письма, но ничего от recidive. Я запускаю:
Fail2Ban v0.8.13
Моя соответствующая глобальная конфигурация идентична той, что вы опубликовали:
banaction = iptables-multiport
mta = sendmail
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"]
action = %(action_mwl)s
Моя начальная конфигурация джейла recidive (который не отправлял электронные письма):
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
#action = iptables-allports[name=recidive]
# sendmail-whois-lines[name=recidive, logpath=/var/log/fail2ban.log]
bantime = 604800 ; 1 week
findtime = 604800
#findtime = 86400 ; 1 day
maxretry = 3
Обратите внимание, что я закомментировал действие recidive по умолчанию. По крайней мере, для меня это было то, что пришло по умолчанию. Я сделал это, потому что хотел, чтобы recidive email работал как ssh, который также использовал действие по умолчанию. С этой конфигурацией... я ничего не получил. Сверчки. Но recidive jail работал. Я не знаю точно, в чем была проблема, но я знал, что должен ее решить. Поэтому я сначала попробовал откомментировать действие. Затем оно все еще работало, но писем не было. Или я так думал. Оказалось, что письма отправлялись на локальную учетную запись root. Я обнаружил их в почтовом ящике /var/mail/[user], на который была перенаправлена почта root. И тогда я понял, что это потому, что destemail не используется в этом действии по умолчанию. В итоге я просто скопировал глобальное действие по умолчанию action_mwl и подправил его, чтобы убрать порт.
Итак, моя окончательная конфигурация jail, которая сработала:
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
#action = iptables-allports[name=recidive]
# sendmail-whois-lines[name=recidive, logpath=/var/log/fail2ban.log]
action = %(banaction)s[name=%(__name__)s, protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"]
Возможно, все это сделано специально или это старая ошибка - я не знаю. Но вот как я заставил его работать. Это может быть слишком поздно, чтобы помочь вам, но, возможно, это поможет следующему в той же лодке...
Как избежать возможной инъекции аргумента?
Узнайте, какие входные данные вы хотите передать, и убедитесь, что аргументы содержат только их.
По крайней мере, убедитесь, что они не содержат символов, характерных для удаленной оболочки.
$1
не представляет особой проблемы, поскольку вы сравниваете его с известными значениями. Хотя вам нужно заключить его в двойные кавычки, иначе он может расшириться до нескольких слов при сравнении, и это может позволить передавать через него забавные значения (что-то вроде 1 -o x
пройдет сравнение).
Используйте if [ "$1" = "s3" ] ; тогда ...
вместо этого.
Что касается $2
и $3
, передача их через ssh
в основном аналогична передаче их в eval
или ш-с
. Любые замены внутри них будут расширены на удалении.
Допустим, мы запустим ssh somehost "echo $var"
.Теперь, если var
содержит $(ls -ld /tmp)
, удаленная командная строка будет echo $(ls -ld /tmp)
, а ls
выполняется на удаленном компьютере. Двойные кавычки переменной не помогут с расширением команды, но одинарные кавычки помогут. С командой, написанной как
ssh somehost "echo '$var'"
, расширение команды не происходит.
Одинарные кавычки внутри переменной по-прежнему представляют собой проблему, так как они прервут одинарные кавычки, так что, по крайней мере, нам нужно проверить это:
case "$var" in *"'"*) echo var has a single-quote; exit 1 ;; esac
Хотя мы могли бы также проверить наличие специальных символов мы не хотим проходить. Знаки доллара начинают большинство расширений, обратные кавычки начинают расширение команд, а кавычки, которым я тоже не доверяю:
case "$var" in *[\'\"\$\`]*) echo var has something funny; exit 1 ;; esac
Но я не уверен, что это все, поэтому лучше просто внести в белый список символы, через которые мы хотим пройти. Если достаточно букв, цифр, тире и подчеркивания:
case "$var" in *[!-_a-zA-Z0-9]*) echo var has something funny; exit 1 ;; esac
Итак, это может быть началом:
function runMyScript {
case "$2" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac
case "$3" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac
if [ "$1" = "s3" ] ; then
ssh somehost "script.sh '$1' '$2' '$3'"
elif [ "$1" = "ec2" ] ; then
ssh somehost "script.sh '$1' '$2'"
else
echo "** Run with s3 or ec2 options"
fi
}
Заметив, что вы использовали функцию runMyScript
вместо runMyScript()
, вы не используете обычную оболочку POSIX. Если это Bash, вы можете переписать совпадения с шаблоном с помощью теста [[...]]
, который поддерживает совпадения с регулярными выражениями.
Новые версии Bash также имеют расширение ${var@Q}
, которое должно создавать содержимое var
в кавычках в формате, который можно повторно использовать в качестве входных данных. Это также может быть полезно, но у меня нет под рукой достаточного количества нового bash, чтобы проверить его.
Кроме того, не верьте мне слепо, что я помню все возможные причуды языка оболочки.
В качестве дополнения к прекрасному ответу @ikkachu:
По сравнению с передачей произвольных строк в eval
или sh -c
, здесь проблема усугубляется:
Ваш вопрос в основном является подмножеством Как выполнить произвольную простую команду по ssh, не зная оболочки входа в систему удаленного пользователя?
Таким образом, ответы здесь применимы.
В частности, если sshd
на удаленном хосте позволяет передавать переменные среды, начинающиеся с LC_*
(как это делают многие развертывания openssh), вы можете сделать следующее:
LC_ARG1=$1 LC_ARG2=$2 LC_ARG3=$3 ssh -o SendEnv='LC_*' host exec sh -c \
\''exec my-script "$LC_ARG1" "$LC_ARG2" "$LC_ARG3"'\'
Очистка ввода это хорошая идея, но обратите внимание, что вы не хотите использовать диапазоны, такие как [AZ]
, если вы не находитесь в локали C. Например, в большинстве локалей системы GNU Ǒ
находится в этом диапазоне, а, например, в локали zh_HK.big5hkscs
этот символ кодируется как 0x88 0x60
. и вы можете распознать 0x60 как кодировку ASCII (и BIG5HKSCS) символа обратной кавычки!
Лучше всего указывать разрешенные символы по отдельности:
is_safe() case $1 in
*[!-_.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*) false;;
esac
Также остерегайтесь пустой строки, которую нужно будет заключать в кавычки (''
поддерживается всеми распространенными оболочками). И остерегайтесь аргументов, начинающихся с -
, которые некоторые инструменты могут принять как опции.