ВАСИЛИЙ ОЗЕРОВ
Настраиваем безопасный роутер на базе FreeBSD
Существует два ошибочных мнения. Одно гласит, что безопасности в настройке сервера много не бывает, другое – что она не нужна вовсе. В первом случае работать в системе становится неудобно, во втором – важная информация не защищена от посторонних. Где же золотая середина?
Речь пойдет о том, как увеличить безопасность FreeBSD, работающей в качестве маршрутизатора между локальной сетью и Интернетом. Так как мы будем настраивать роутер, то о большом количестве пользователей на нем речи не идет. Также я предполагаю, что компьютер имеет доступ в Интернет с внешним IP-адресом.
Говоря о безопасности в общем (не только о компьютерной), мы неизменно возвращаемся к одному очень простому и действенному правилу: все, что человек создал, он может и уничтожить. Это правило работает везде и всегда. Возвращаясь к безопасности операционных систем, можно говорить об их защите очень долго, но все вернется опять к этому правилу: операционную систему создал человек, и, следовательно, всегда найдется другой человек, который сможет обойти ее защиту, какой бы мощной она ни была.
Безопасность
Безопасность системы в целом складывается из трех факторов:
- Безопасность ядра.
- Безопасность установленного в ней ПО.
- Человеческий фактор.
Рассмотрим каждый из этих факторов подробно.
Безопасность ядра
Большинство взломов происходит из-за ошибок в ядре. Ядро для операционной системы – это основа: оно управляет всеми операциями, производимыми в компьютере, и, следовательно, без ядра работа системы невозможна, в частности, из-за отсутствия контроля за входными значениями функций. Функции работают на уровне ядра и как следствие имеют абсолютные привилегии, поэтому некоторые хакеры усердно ищут уязвимости для повышения привилегий в системе.
Так как для семейства UNIX-систем ядра распространяются в открытом исходном коде, то для нахождения уязвимостей достаточно знать язык C.
Человек, нашедший уязвимость, может сообщить о ней разработчику или использовать уязвимость для взлома.
В первом случае разработчик, как правило, в кратчайшие сроки устранит уязвимость и выложит обновления для ядра. Вам же как системному администратору достаточно вовремя обновить систему (ядро).
Второй вариант происходит достаточно редко и грозит взломом многих серверов. Опасен он тем, что вы думаете, что система надежна защищена, хотя на самом деле это не так. Рано или поздно, разработчики узнают о существовании уязвимости и все возвращается к первому случаю.
Безопасность ПО
Уязвимости в программном обеспечении находят гораздо чаще, нежели в самой системе. Если программа достаточно популярна, то в ней будут стараться найти уязвимости, чтобы получить возможность взломать достаточно большое количество серверов. Человек, который нашел уязвимость, может пойти двумя путями, которые аналогичны описанным ранее. Автор программы рано или поздно узнает об уязвимости и выпустит обновление к программе. А ваша задача – всего лишь вовремя обновить ПО.
Человеческий фактор
Эта составляющая является главной для безопасности системы в целом! Ни одна система не может «похвастаться» безопасностью без дополнительной настройки. Все ОС придется аккуратно настроить перед тем, как они смогли бы противостоять хакерским атакам.
На основании вышеизложенного понятно, что от грамотной настройки сервера и его поддержки зависит практически все, а выполнить эти требования может только компетентный специалист. Следовательно, говоря о безопасности ОС, мы должны сравнивать настройки систем, а не сами системы. Если у кого-то взломали FreeBSD, то это не говорит о том, что вся система FreeBSD уязвима, это говорит только о том, что ее неправильно настроили.
Как настроить FreeBSD
Итак, переходим от теории к практике. Настраивать систему мы будем также по трем направлениям, описанным ранее.
Ядро
Итак, у вас установлена FreeBSD со стандартным ядром GENERIC, которое включает в себя поддержку избыточного количества устройств и функций. Это достаточно просто объяснить: разработчик не знает, какая у вас система, какие устройства и т. д., а стандартное ядро практически всегда позволяет загрузиться на любом компьютере. Конфигурирование ядра – задача довольно тривиальная. Требуется совсем немного времени, чтобы «выкинуть» из конфигурационного файла ядра все, что не нужно, потом, добавив дополнительные возможности, перекомпилировать его. Зачем пересобирать ядро:
- Ядро будет пытаться определить только те устройства, которые установлены в компьютере, поэтому загрузка системы будет происходить намного быстрее.
- Размер ядра уменьшается, и оперативная память освобождается.
- Увеличивается безопасность благодаря отключению ненужных функций.
Отключение поддержки ненужных устройств я оставляю на ваше усмотрение, подробности смотрите на официальном сайте FreeBSD (http://www.freebsd.org/doc/ru_RU.KOI8R/books/handbook/kernelconfig-config.html). Сразу добавляем в конфигурационный файл опции для firewall: я предпочитаю использовать в качестве firewall pf, поэтому речь пойдет о нем. Приступаем к конфигурированию и компиляции ядра (комментарии начинаются с «//», их писать не нужно!):
# cd /usr/src/sys/i386/conf/
# cp GENERIC new
# cat >> new
// Включаем поддержку firewall
device pf
device pflog
device pfsync
// Запрещает перезагрузку клавишами <ctrl+ alt +del>
options SC_DISABLE_REBOOT
// Включаем поддержку ALTQ для шейпинга пакетов
options ALTQ
Конфигурируем ядро:
# config new
Kernel build directory is ../compile/new
Don’t forget to do ``make cleandepend; make depend’’
|
Компилируем и устанавливаем:
# cd ../compile/new && make cleandepend && make depend && make && make install
Перезагружаемся:
# reboot
Должно быть загружено новое ядро, если этого не произошло, то старое лежит в /boot/kernel.old.
У меня после удаления всех ненужных опция ядро уменьшилось более чем в два раза.
Механизм sysctl
Это достаточно мощное средство управления системой: с помощью sysctl можно смотреть и изменять параметры системы. Так как наша машина должна выполнять роль роутера, то желательно изменить следующие значения:
// Включаем проброс пакетов через интерфейсы
# sysctl net.inet.ip.forwarding=1
// Генерируем случайный идентификатор IP-пакетов
# sysctl net.inet.ip.random_id
// Ограничиваем количество ICMP-ответов
# sysctl net.inet.icmp.icmplim=10
// Отключаем реагирование на попытку обратиться к закрытым портам
# sysctl net.inet.tcp.blackhole=2
# sysctl net.inet.udp.blackhole=1
// Запрещаем пользователям смотреть чужие процессы
# sysctl security.bsd.see_other_gids=0
# sysctl security.bsd.see_other_uids=0
Это минимум, который необходимо изменить. Чтобы после перезагрузки все настройки остались прежними, внесите изменения в /etc/sysctl.conf.
Есть еще одна очень интересная переменная, которую я хотел бы описать, – это kern.securelevel. Securelevel может принимать значения от -1 до 3. Давайте рассмотрим последние три случая, так как -1 и 0 являются небезопасными режимами работы и ставятся по умолчанию:
- 1. Безопасный режим. В этом режиме вы не можете снимать модификационные флаги с файлов (даже от имени суперпользователя – root), смонтированные дисковые устройства, а также /dev/mem /dev/kmem не могут быть открыты для записи. Также нельзя подгружать/выгружать модули ядра.
- 2. Повышенная безопасность. В дополнение к предыдущим требованиям запрещена прямая запись на диски, независимо от того, смонтированы они или нет.
- 3. Режим безопасности сети. Режим повышенной безопасности плюс нельзя изменять правила firewall.
Какой режим поставить – выбирать вам (у меня стоит второй). Вам не нужно перекомпилировать код ядра каждый раз для добавления новых функций, достаточно подгрузить необходимый модуль ядра. Например, для работы стека bluetooth используется модуль ng_ubt. При захвате системы хакер скорее всего попытается подгрузить новый модуль для того, чтобы скрыть свое нахождение в системе, но если устновить второй или третий режим безопасности, то для загрузки модуля придется перезагружать систему, что вряд ли не останется незамеченным.
Настройка безопасности системы
Давайте поменяем хеширование паролей md5, которое стоит по умолчанию, на более стойкое к взломам blowfish. Для начала нужно отредактировать /etc/login.conf, в котором описываются классы пользователей, заменив:
:passwd_format=md5:\
на
:passwd_format=blf:\
Теперь можно создать базу:
# cap_mkdb /etc/login.conf
Для того чтобы пароли пользователей теперь хешировались с помощью blowfish, нужно отредактировать /etc/auth.conf, заменив:
crypt_default=md5
на
crypt_default=blf
После этого в /etc/master.passwd все пароли будут начинаться с $2, что указывает системе на использование хешей по алгоритму blf.
Теперь пользователям, которым не разрешено иметь интерактивный шелл, в систему нужно поставить:
shell: /sbin/nologin
Этот шелл дает два преимущества:
- При попытке регистрации пользователя в системе /sbin/nologin возращает ответ о том, что регистрация пользователя в системе невозможна.
- Попытка входа записывается в логи.
После этого нужно разобраться в правах к некоторым системным файлам и директориям:
# chmod 0600 /etc/login.conf /etc/syslog.conf /etc/newsyslog.conf /etc/rc.conf /etc/hosts.allow
# chmod 0700 /root/
Настройка программного обеспечения
Для начала обновим систему. В первую очередь – исходники, потом – коллекцию портов. Для обновления системы будем использовать cvsup. Редактируем supfile:
*default host=cvsup5.ru.FreeBSD.org
*default base=/usr
*default prefix=/usr
*default release=cvs tag=RELENG_6_0
*default delete use-rel-suffix
*default compress
src-base
src-bin
src-contrib
src-etc
src-gnu
src-include
src-kerberos5
src-kerberosIV
src-lib
src-libexec
src-release
src-sbin
src-share
src-sys
src-tools
src-usrbin
src-usrsbin
src-crypto
src-secure
src-sys-crypto
Таг RELENG_6_0 используется для исправлений исходного кода системы для увеличения безопасности. Теперь непосредственно запускаем cvsup:
# cvsup -g -L 2 /usr/local/etc/supfile
Обновления можно взять с cvsup5.ru.FreeBSD.org (параметр host в supfile), причем скачиваются только обновленные файлы, а не все целиком, отсюда такое маленькое потребление трафика. Точно сказать нельзя, сколько придется скачать, все зависит от количества исправлений, но точно менее 10 Mб.
Теперь смотрим, если уязвимость обнаружена в ядре, то придется его пересобрать. Если в системной утилите, то пересобирать следует только программу.
Обновление коллекции портов удобнее делать с помощью программы portsnap, которая теперь является частью системы. Пользоваться ей намного проще, чем cvsup:
При первом запуске:
# portsnap fetch
# portsnap extract
# portsnap update
При последующих запусках:
# portsnap fetch
# portsnap update
Portsnap только в первый раз скачивает всю коллекцию портов(~38 Mб), потом же качаются только обновленные файлы.
Настройка pf
На любом компьютере, подключенном к сети, обязательно должен стоять firewall. Причем он должен быть корректно настроен. Я приведу несколько простых правил, которые позволят фильтровать входящие соединения:
prov_if="sk0"
int_if="rl0"
internal_net="172.16.0.0/24"
me="172.16.0.1"
LAN_to_INT="{ftp,ftp-data,www,https,ssh,smtp,pop3,nntp,8080,ntp,411,5190}"
scrub in all
# Транслируем все пакеты к smtp-серверам
nat on $prov_if from $internal_net to any port 25 -> $prov_if
# Транслируем все пакеты к pop-серверам
nat on $prov_if from $internal_net to any port 110 -> $prov_if
# Настраиваем перенаправление всех пакетов, идущих к www-серверу в DMZ
rdr on $prov_if proto tcp from any to $prov_if port www -> 172.16.1.3 port www
# Включаем прозрачное проксирование
rdr on $int_if proto tcp from $internal_net to any port 80 -> 172.16.0.1 port 3128
# in packs on prov_if
# Блокируем все входящие соединения
block in on $prov_if from any to any
# Разрешаем пинги
pass in on $prov_if inet proto icmp from any to $prov_if icmp-type 8 keep state
# Разрешаем соединяться с ssh-сервером
pass in on $prov_if inet proto tcp from any to $prov_if port 22 keep state
# Доступ к WWW
pass in on $prov_if inet proto tcp from any to $prov_if port www keep state
# Разрешаем соединяться с нашим почтовым сервером
pass in on $prov_if inet proto tcp from any to $prov_if port 25 keep state
# out packs on prov_if
# Блокируем все входящие соединения
block out on $prov_if from $prov_if to any
# Разрешаем пинги от нас
pass out on $prov_if inet proto icmp from $prov_if to any icmp-type 8 keep state
# Разрешаем обращаться на Web
pass out on $prov_if inet proto tcp from $prov_if to any port www keep state
# На ftp
pass out on $prov_if inet proto tcp from $prov_if to any port ftp keep state
# На ssh
pass out on $prov_if inet proto tcp from $prov_if to any port ssh keep state
# Разрешаем запросы к DNS
pass out on $prov_if inet proto udp from $prov_if to any port 53 keep state
# in packs on int_if
# Блокируем все входящие соединения
block in on $int_if from $internal_net to $me
pass in on $int_if inet proto tcp from $internal_net to $me port 22 keep state
# Разрешаем локальной сети обращаться к нашему DNS-серверу
pass in on $int_if inet proto udp from $internal_net to $me port 53 keep state
# out packs on $int_if
# Запрещаем все исходящие от нас соединения в локальную сеть
block out on $int_if from $me to $internal_net keep state
# Разрешаем пинги от нас
pass out on $int_if inet proto icmp from $me to $internal_net icmp-type 8 keep state
При составлении правил главная идея такова: запрещаем все, а потом разрешаем только то, что нужно.
Теперь переходим к настройке безопасного доступа к серверу OpenSSH. Раньше терминальный доступ к серверу обычно был предоставлен только telnet-сервером, но его сменил безопасный ssh-сервер. Но при настройках по умолчанию – это хорошая мишень для хакера. Итак, при настройке ssh-сервера, мы поступим так: составим два конфигурационных файла специально для двух сетей:
- локальная сеть;
- Интернет.
В локальной сети мы разрешим авторизацию по паролю, а из Интернета разрешим авторизацию только по ключам, что не позволит подобрать пароль.
# sshd_config_1 (Локальная сеть):
Port 22
Protocol 2
ListenAddress 172.16.0.1
PermitRootLogin no
PasswordAuthentication yes
MaxStartups 2:90:5
AllowGroups ssh
Banner /etc/motd
Subsystem sftp /usr/libexec/sftp-server
# sshd_config_2 (Интернет):
AllowGroups ssh
Banner /etc/motd
ListenAddress 213.251.193.69
LogLevel VERBOSE
MaxStartups 2:90:5
PasswordAuthentication no
PermitRootLogin no
Port 22
Protocol 2
Subsystem sftp /usr/libexec/sftp-server
SyslogFacility AUTH
Это опять же минимальные настройки, об остальных можно прочитать, например, в руководстве (man sshd_config). Также изменим /etc/motd:
*********************************************************
This is a private system!!! All connection attempts are
logged and monitored. All unauthorized connection
attempts will be investigated and
handed over to the proper authorities.
*********************************************************
Так как мы указали, что из Интернета можно аутентифицироваться только по ключам, то придется эти самые ключики сгенерировать:
$ ssh-keygen -t rsa -b 4096
$ cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys
Теперь нужно «спрятать» id_rsa в надежное место и можно логиниться с помощью этого ключа, предупреждаю, что для putty придется генерировать ключи специальной утилитой – puttygen.
Отчеты системы
Последний фактор – человеческий. Сейчас мы постараемся сделать отчеты о работе системы как можно более подробными. Так как у нас в системе практически все ПО установлено из портов, то было бы неплохо проверять уязвимость портов. Для этого будем использовать специальную утилиту portaudit:
# cd /usr/ports/security/portaudit
# make install clean
Настраивать ее не нужно, для проверки установленных пакетов достаточно выполнить:
# /usr/local/sbin/portaudit -Fda
При попытке установить программу из портов portaudit проверит и выдаст предупреждение, если данный порт содержит уязвимость. Также информация об уязвимостях в установленном ПО будет включаться в ежедневный отчет о безопасности системы.
Так как сервер выполняет роль шлюза, то на нем редко будут меняться системные файлы, следовательно, можно настроить аудит системных файлов. В данной области самой распространенной из бесплатных систем является tripwire:
# cd /usr/ports/security/tripwire
# make install clean
После установки база файлов начнет создаваться автоматически, желательно посмотреть, каких файлов она не нашел. После этого редактируем файл политик /usr/local/etc/tripwire/twpol.txt. Изменять нужно две вещи:
- Так как мы хотим получать отчеты по email, то после каждой строки severity нужно дописывать строку: emailto = qw@er.ty.
- Нужно закомментировать строки с файлами, которых у вас в системе нет.
После этого нужно создать файл политик:
# twadmin --create-polfile twpol.txt
Теперь осталось инициализировать tripwire:
# tripwire --init
Проверку файлов можно осуществлять следующим образом:
# tripwire --check
Желательно прописать запуск tripwire в cron.
Теперь установим еще одну полезную утилиту chkrootkit, которая будет проверять наличие известных ей rootkit в системе:
# cd /usr/ports/security/chkrootkit/
# make install clean
Проверить систему можно так:
# chkrootkit | mail root
Таким образом, отчет о проверке по почте придет к администратору. Также советую прописать эту строку в cron. Единственная проблема, связанная с chkrootkit, заключается в том, что программа написана на sh и как следствие может быть «переписана» взломщиком, поэтому желательно добавить проверку chkrootkit в tripwire.
Заключение
Таким способом мы улучшили безопасность системы в несколько раз:
- Установлен и настроен firewall.
- Настроен безопасный доступ к системе (OpenSSH).
- Увеличено количество информации, поступаемой от системы.
Остальное дело за вами: следить за уязвимостями, вовремя обновлять систему и софт, установленный в ней, следить за отчетами безопасности и всегда быть на страже.