Рубрика:
Безопасность /
Безопасность
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
Дмитрий Рощин
VPN на основе протокола PPTP: как повысить безопасность?
В настоящее время большинство специалистов считают протокол PPTP ненадежным с точки зрения безопасности и не рекомендуют его использование для создания виртуальных частных сетей (VPN). Однако существует способ построения VPN на основе этого протокола с уровнем защищенности, достаточным для использования в корпоративной среде, и минимальными финансовыми затратами.
Нелегкая судьба протокола PPTP
Протокол PPTP (Point-to-Point Tunneling Protocol) разработан компанией Microsoft совместно с компаниями Ascend Communications, 3Com/Primary Access, ECI-Telematics и US Robotics. Этот протокол получил статус интернет-стандарта, но так и не был утвержден.
Для организации туннеля в PPTP используется протокол GRE (Generic Routing Encapsulation), а для шифрования трафика используется MPPE (Microsoft Point-to-Point Encryption), протокол для шифрования пакетов протокола PPP потоковым шифром RC4.
Фактически задача PPTP состоит в организации шифрованного туннеля, внутри которого будет работать протокол PPP.
GRE не единственный протокол транспортного (согласно модели OSI) уровня, используемый в PPTP – для организации управляющего канала PPTP использует протокол TCP (порт 1723).
В реализации Microsoft поддерживаются следующие методы аутентификации: PAP, CHAP, SPAP, MSCHAP v1, MSCHAP v2, EAP. Несмотря на наличие ряда «врожденных» дефектов, о которых я еще скажу далее, данный протокол до сих пор активно используется многими организациями благодаря тому, что до появления L2TP/IPSEC это был единственный VPN-протокол, поддержка которого была встроена в ОС Windows.
Итак, как настроить PPTP VPN таким образом, чтобы обеспечить максимально возможный для данного протокола уровень безопасности? Думаю, что предложенное решение будет интересно еще и как очередной пример взаимодействия в рамках конкретной задачи коммерческого программного обеспечения с программным обеспечением, имеющим открытый исходный код.
В первоначальном виде протокол PPTP представлял собой настоящее решето. Буквально все его составляющие были уязвимы к различным видам атак. Пароли в виде LM-хэшей; алгоритм MSHAP v1 (сплошное недоразумение); шифрование MPPE (многократное использование ключей шифрования, атаки на шифр RC4, генерация ключей шифрования на основе пароля пользователя); полное отсутствие аутентификации сервера и проверки подлинности шифрованных пакетов; отсутствие шифрования во время установления PPP-соединения; нет никакой защиты канала управления и т. д.
Все эти уязвимости были выявлены в 1998 году Брюсом Шнаером [1]. После чего Microsoft провела работу по усилению безопасности и улучшению качества кода реализации PPTP. Новая версия протокола получилась более защищенной, появилась вторая версия протокола MSCHAP.
Однако в скором времени все тот же неугомонный Брюс Шнаер в 1999 году опять провел криптографический анализ уже обновленного протокола [2]. Результаты снова оказались неутешительными, это и понятно, ведь многие из уязвимостей существуют из-за недоработок в дизайне протокола. Осталась генерация ключей шифрования на основе пароля пользователя, равно как и отсутствие проверки подлинности шифрованных пакетов, шифрование во время установления PPP-соединения по-прежнему отсутствует.
В 2003 году Джошуа Райт написал утилиту asleap [3], которая за доли секунд взламывает слабые пароли, защищенные алгоритмом MSCHAPv2, а чуть позже в нее был добавлен функционал работы с PPTP (см. рис. 1). Эта утилита изначально разрабатывалась для атак на патентованный протокол Cisco Systems LEAP. Многие специалисты по информационной безопасности, увидев ее в действии, начали призывать махнуть рукой на ущербный от рождения протокол, мол, горбатого могила исправит, и переходить на L2TP/IPsec.
Рисунок 1. Демонстрация работы asleap
Конечно, уровень безопасности протокола IPSEC на порядок выше, чем PPTP, однако есть один нюанс, который позволяет и PPTP от Microsoft отстоять свое право на существование. И вот в чем он заключается.
Свет в конце туннеля
Главная уязвимость PPTP на сегодняшний день заключается в слабости алгоритмов парольной аутентификации (MSCHAP, MSCHAPv2), а также в том, что при использовании этих алгоритмов сессионные ключи MPPE получаются из пользовательского пароля [4]. Ведь редкий пользователь установит себе пароль типа «3hEML@4rj897#KJK$$», его будет сложновато запомнить, а вот, например, пароль «boomer» запомнить легко. А наличие простого пароля хотя бы у одного пользователя делает возможным проникновение злоумышленника во внутреннюю сеть организации. Здесь мы наблюдаем изначально неправильный подход к решению задачи – безопасность системы аутентификации и шифрования ставится в зависимость от пользователя.
Ситуация в корне меняется, если вместо парольной аутентификации использовать аутентификацию EAP-TLS – расширение протокола PPP, разработанное Microsoft, которое позволяет использовать для взаимной аутентификации SSL-сертификаты. Этот метод аутентификации лишен недостатков MSCHAPv [1, 2], так как аутентификация пользователя производится по уникальному ключу, который генерируется на основе случайных данных. На сегодняшний день использование SSL-сертификатов является одним из самых надежных методов аутентификации. Тот факт, что с его использованием построено большинство современных систем электронной коммерции и интернет-банков, говорит о многом.
В случае использования сертификатов, с длиной ключа 2048 бит на сегодняшний день, EAP-TLS практически невозможно взломать.
Сеансовые ключи MPPE в данном случае генерируются на основе ключа TLS master secret, полученного в процессе аутентификации TLS. Клиенты также получают возможность проверки подлинности сервера еще на этапе аутентификации. Кроме того, использование EAP-TLS дает нам возможность применять двухфакторную аутентификацию клиентов, используя смарт-карты или электронные ключи e-token. Такая конфигурация позволяет выжать максимум безопасности из протокола PPTP и достичь компромисса между безопасностью, удобством работы пользователей и стоимостью всего решения.
Рассмотрим пример практической реализации VPN с использованием двухфакторной аутентификации по протоколу EAP-TLS.
Пример задачи
Предположим, что согласно ТЗ, полученному от IT-директора компании Testco, нам необходимо обеспечить безопасный удаленный доступ в локальную сеть компании 3 группам сотрудников (см. таблицу).
Техническое задание для обеспечения безопасного удаленного доступа в локальную сеть компании
№
|
Группа
|
Пользователи
|
IP-адреса серверов, на которые необходимо организовать доступ клиентов
|
Порт
|
Служба
|
1
|
Администраторы
|
Игорь Иванов
|
192.168.10.10
|
3389
|
RDP
|
2
|
Пользователи intranet-сайта
|
Ольга Петрова
|
192.168.10.11
|
80
|
HTTP
|
3
|
Пользователи терминалов Citrix
|
Владимир Сидоров
|
192.168.10.{12-15}
|
1494
|
ICA
|
Может быть, данное деление не слишком удачное, ведь оно введено только для демонстрации возможности использования разграничения доступа для пользователей VPN.
Выбор ПО и «железа»
В качестве платформы для сервера мы будем использовать последнюю стабильную версию FreeBSD 6.2. Можно использовать и платформу Windows, но тогда нам понадобится Windows 2003 Enterprise Edition Server, на котором придется поднимать центр сертификации, а поднимать и администрировать ЦС только ради VPN это, на мой взгляд, стрельба из пушки по воробьям. К тому же использование ПО с открытым исходным кодом значительно уменьшает стоимость всего решения.
Почему именно FreeBSD, а не другая UNIX-система? Главным звеном решения является пакет MPD (Multi-link PPP daemon), основа которого – это модули ядра FreeBSD. Использование же MPD в свою очередь обусловлено использованием функционала NAS ACL, о котором будет сказано далее. К сожалению, похожий проект Poptop не имеет данного функционала.
MPD NAS ACL можно использовать только в связке с сервером RADIUS. Из возможных вариантов серверов RADIUS был выбран FreeRADIUS, так как это наиболее популярный и зрелый открытый RADIUS-сервер. Кстати, его использование плюс ко всему дает нам возможность вести учет работы клиентов VPN.
Хранить информацию о пользователях и группах, а также данные учета их работы будем в БД MySQL.
При желании использовать веб-интерфейс можно прикрутить Dialup-admin, который входит в состав пакета FreeRADIUS, однако этот вопрос выходит за рамки статьи.
В качестве клиентской ОС, конечно же, Windows, иначе зачем использовать PPTP?
Настройки, описанные далее, подойдут как Windows 2000 SP4, так и Windows XP SP2, так как процесс конфигурирования VPN-соединений для этих ОС практически идентичен.
Для обеспечения двухфакторной аутентификации можно использовать как Aladdin e-token, так и Rainbow iKey. Для достижения более высокого уровня безопасности я советую использовать e-token PRO64, так как он умеет работать с ключами длиной в 2048 бит. И поддержка e-token как продукта гораздо лучше, чем поддержка iKey. В этой статье рассматривается именно вариант с e-token PRO64.
«Железо» для сервера может быть практически любое, совместимое с FreeBSD 6.2 (см. список поддерживаемого оборудования на сайте freebsd.org). Минимальные требования по «железу» к описанной в этой статье системе – это процессор Celeron со 128 Мб оперативной памяти, далее все зависит от количества клиентов, хотя я все же рекомендую поставить хотя бы 512 Мб оперативной памяти.
Схема доступа
Из всех вариантов расположения VPN-шлюза наиболее предпочтительной является схема с расположением его в демилитаризованной зоне (DMZ), при этом локальная сеть организации, DMZ и Интернет отделены друг от друга межсетевым экраном (МСЭ). Этот вариант наиболее безопасен, так как позволяет контролировать трафик как между VPN-шлюзом и Интернетом, так и между VPN-шлюзом и локальной сетью (см. рис .2).
Рисунок 2. Схема VPN компании Testco
Далее, основываясь на одном из основных принципов безопасности – минимизации привилегий, определим политику доступа для 3 групп пользователей VPN, описанных выше.
Мы должны ограничить доступ клиентов VPN к локальной сети компании только теми ресурсами, которые им действительно необходимы.
Очевидно, что у пользователей второй и третьей групп не должно быть доступа к ресурсам друг друга и первой группы.
Даже администраторам не следует предоставлять удаленный доступ ко всей сети только на терминальный сервер по той причине, что не все администраторы должным образом следят за безопасностью своих компьютеров. Поэтому если не ограничить доступ, вирус с зараженного домашнего компьютера администратора может прорваться в локальную сеть компании.
Контролировать доступ мы будем, используя такую замечательную возможность MPD, как NAS ACL. NAS (Network Access Server) – это сервер доступа, то есть сам MPD, а ACL (Access Control List) – это списки доступа, в данном случае это правила IPFW (родной пакетный фильтр FreeBSD).
По умолчанию весь трафик с адресов VPN-клиентов будет заблокирован, но когда клиент пройдет авторизацию, сервер RADIUS определит группу, в которую входит данный клиент, и выдаст MPD-атрибут (один или несколько) mpd-rule, определенный для данной группы. Значением этого атрибута является правило IPFW, которое откроет доступ на разрешенный для него ресурс, после отключения клиента правило будет удалено.
Для нормального функционирования VPN-шлюза в DMZ на МСЭ необходимо разрешить следующие типы трафика:
- Прохождение GRE-пакетов с любого IP на VPN и обратно на интерфейсах inet0 и dmz0.
- Прохождение TCP-пакетов с любого IP на VPN (порт 1723) и обратно на интерфейсах inet0 и dmz0.
- Разрешить на интерфейсах (inet0 и lan0) все пакеты с VPN-шлюза в локальную сеть и обратно согласно нашей политике доступа (TCP с VPN-шлюза на 192.168.10.10 порт 3389 и на порт 192.168.10.11/24 80, и на (192.168.10.12–192.168.10.15) порт 1494).
Пример конфигурационного файла pf.conf для пакетного фильтра OpenBSD PF:
vpn_s="192.0.2.34"
vpnnet="172.17.0.0/24"
rdpterm="192.168.0.10"
intranetweb="192.168.0.11"
table <citrixfarm> const { 192.168.0.12, 192.168.0.13, 192.168.0.14, 192.168.0.15 }
block log all
pass quick on { inet0, dmz0 } inet proto gre from any to $vpn_s
pass quick on { inet0, dmz0 } inet proto gre from $vpn_s to any
pass in quick on inet0 proto tcp from any to $vpn_s port pptp keep state tag INET_DMZ
pass in quick on dmz0 proto tcp from $vpnnet to $rdpterm port rdp keep state tag DMZ_LAN
pass in quick on dmz0 proto tcp from $vpnnet to $intranetweb port http keep state tag DMZ_LAN
pass in quick on dmz0 proto tcp from $vpnnet to <citrixfarm> port ica keep state tag DMZ_LAN
pass out quick on dmz0 all keep state tagged INET_DMZ
pass out quick on lan0 all keep state tagged DMZ_LAN
Кроме того, на МСЭ необходимо прописать маршрут до сети VPN, иначе обратные пакеты не дойдут туда. Для большинства UNIX-систем это будет выглядеть так:
fire1# route add 172.17.0.0/16 192.0.2.34
Конфигурация пакетных фильтров
Для запуска IPFW необходимо добавить следующую строку в файл /etc/rc.conf:
firewall_enable="YES"
firewall_type="VPN"
Тип VPN необходимо определить в файле /etc/rc.firewall следующим образом:
[Vv][Pp][Nn])
# Диапазон адресов, которые будут выдаваться клиентам VPN, не должен пересекаться с адресами
# локальной сети клиента, поэтому не рекомендуется использовать диапазон 192.168
vpnnet="172.17.0.0/24"
setup_loopback
# Блокировать любой трафик от VPN-клиентов
${fwcmd} add 64000 deny all from $vpnnet to any
# Нет необходимости фильтровать другой трафик, так как VPN-шлюз находится в DMZ
${fwcmd} add 65000 pass all from any to any
;;
MPD будет добавлять правила для пользователей VPN начиная с номера 10000.
После внесения изменений в конфигурационные файлы, если вы работаете удаленно, то необходимо перезагрузить машину, если же вы работаете с консоли, стартуете IPFW:
vpn-s# /etc/rc.d/ipfw start
Установка и конфигурация mpd
Из коллекции портов FreeBSD устанавливаем первую стабильную версию mpd4:
vpn-s# cd /usr/ports/net/mpd
vpn-s# make install clean
vpn-s# echo 'mpd_enable="YES"' >> /etc/rc.conf
Mpd конфигурируется с помощью 3 файлов.
Файл mpd.conf:
default:
# Создаем 50 netgraph интерфейсов
load pptp0 # Загрузка разделов конфига
load pptp1
load pptp2
...
load pptp49
pptp0:
# Создать новый интерфейс
new -i ng00 pptp0 pptp0
# Назначить клиенту IP-адрес, первый параметр – IP-адрес конца туннеля со стороны сервера,
# 2-й – IP-адрес клиента (маской задается диапазон сети из которого будет назначен адрес)
set ipcp ranges 172.18.0.1/32 172.18.1.1/32
# Загрузить общие для всех интерфейсов параметры конфигурации
load pptp_standart
pptp1:
new -i ng01 pptp1 pptp1
set ipcp ranges 172.18.0.1/32 172.18.1.2/32
load pptp_standart
pptp2:
new -i ng02 pptp2 pptp2
set ipcp ranges 172.18.0.1/32 172.18.1.3/32
load pptp_standart
pptp99:
new -i ng49 pptp49 pptp49
set ipcp ranges 172.18.0.1/32 172.18.1.50/32
load pptp_standart
pptp_standart:
# Отключить режим работы интерфейса «по требованию»
set iface disable on-demand
# Установить тип канала (описание типов смотрите в файле mpd.links)
set link type pptp
# Мы не будем выдавать адрес DNS-сервера, так как теоретически есть возможность подменить
# выдаваемый сервером адрес, сессия IPCP не шифруется и не производится аутентификация пакетов
# set ipcp dns 127.0.0.1
set iface enable proxy-arp
# Включить сжатие данных
set bundle enable compression
set ccp yes mppc
# Включить 128-битное шифрование mppe
set ccp yes mpp-e128
# Требовать шифрование
set bundle yes crypt-reqd
# IP-адрес сервера vpn-s.testco.ru (необходимо заменить на реальный IP VPN-шлюза
set pptp self 192.0.2.34
# Принимать входящие соединения по протоколу pptp
set pptp enable incoming
# Не инициировать соединения по протоколу pptp
set pptp disable originate
# Отключить механизм «windowing» определенный протоколом. Этот механизм является
# дизайнерской ошибкой. Его отключение улучшает производительность, однако не все клиенты
# будут нормально работать без этого механизма (Windows XP SP2 работает без проблем)
set pptp disable windowing
# Устанавливаем MTU и MRU для канала PPP. Очень важно установить эти значения меньше,
# чем по умолчанию (1500), для того, чтобы избежать фрагментации пакетов GRE.
# Особенно это важно при использовании eap-tls, так как сертификат с ключем длиной
# в 2048 бит, не получится уместить в одном пакете
set link mtu 1420
set link mru 1420
# Включаем механизм mssfix для TCP. Этот механизм заботится о том, чтобы максимальный размер
# сегмента TCP, не превышал размер, заданный параметром MTU
set iface enable tcpmssfix
# Данный для доступа к серверу RADIUS (IP, логин, пароль, порт для авторизации, порт для учета)
set radius server 127.0.0.1 mpd Super!P33a 1812 1813
# Таймаут для RADIUS
set radius timeout 10
# Дополнительный конфигурационный файл для RADIUS
set radius config /usr/local/etc/mpd4/radius.conf
# Количество попыток соединения с сервером RADIUS
set radius retries 3
# Включить учет RADIUS
set auth enable radius-acct
# Включить авторизацию RADIUS
set auth enable radius-auth
# Включить eap
set link enable eap
# Проксировать eap-запросы
set eap enable radius-proxy
Файл mpd.links:
pptp0:
set link type pptp
pptp1:
set link type pptp
pptp2:
set link type pptp
…
pptp49:
set link type pptp
Файл radius.conf:
# Данные для соединения с сервером учета
acct 127.0.0.1 Super!P33a
# Данные для соединения с сервером авторизации и аутентификации
auth 127.0.0.1 Super!P33a
Конфигурация FreeRADIUS
Если FreeRADIUS устанавливается из портов, его файлы конфигурации по умолчанию хранятся в директории /usr/local/etc/raddb:
- radius.conf – главный конфигурационный файл FreeRADIUS;
- clients.conf – файл, в котором хранятся описание клиентов RADIUS (не путать с клиентами VPN);
- eap.conf – файл конфигурации протокола EAP;
- sql.conf – файл конфигурации работы с БД;
- dictionary – файл, в котором содержится словарь атрибутов RADIUS;
- hints – необходим для работы модуля prerocess;
- huntgroups – необходим для работы модуля prerocess.
Главный конфигурационный файл радиуса на первый взгляд очень огромный и устрашающий. Но если мы выбросим из него все лишнее, оставив только директивы, необходимые для работы нашего VPN-сервера, получится компактный и легко читаемый конфигурационный файл:
# Определение путей, необходимых для работы сервера
prefix = /usr/local
exec_prefix = ${prefix}
sysconfdir = ${prefix}/etc
localstatedir = /var
sbindir = ${exec_prefix}/sbin
logdir = /var/log
raddbdir = ${sysconfdir}/raddb
radacctdir = ${logdir}/radacct
confdir = ${raddbdir}
run_dir = ${localstatedir}/run/radiusd
log_file = ${logdir}/radius.log
libdir = ${exec_prefix}/lib
pidfile = ${run_dir}/radiusd.pid
checkrad = ${sbindir}/checkrad
max_requests = 512 # Максимальное количество запросов
# Слушать только на локальном интерфейсе
bind_address = 127.0.0.1
hostname_lookups = no # Не разрешать имена хостов
# Не убирать пробелы из имен пользователей
nospace_user = no
security { # Настройки безопасности
# Ограничение максимального количества принимаемых атрибутов до 200
max_attributes = 200
reject_delay = 1 # Задержка после отказа в доступе 1с
# Сервер не будет отвечать на запросы типа Status-Server
status_server = no }
# Подключить файл с конфигурацией клиентов NAS
$INCLUDE ${confdir}/clients.conf
snmp = no # Не использовать SNMP
thread pool { # Конфигурация потоков
start_servers = 5 # Начальное количество потоков 5
# Максимальное количество потоков 32
max_servers = 32
# Минимум свободных потоков 3
min_spare_servers = 3
# Максимум свободных потоков 10
max_spare_servers = 10
max_requests_per_server = 0
# Предельное значение выполненных запросов после которого поток останавливается
#(необходимо использовать при утечках ресурсов; нет необходимости задавать
# это значение при нормальной работе сервера)
}
modules { # Конфигурация модулей
# Подключаем отдельный конфигурационный файл для EAP
$INCLUDE ${confdir}/eap.conf
mschap { # Разрешаем использовать MSCHAP
}
# Модуль создает уникальный идентификатор сессии на основе
# нижеследующих атрибутов и добавляет его в учетные пакеты
acct_unique {
key = "User-Name, Acct-Session-Id,
NAS-IP-Address, Client-IP-Address, NAS-Port"
}
# Подключаем отдельный конфигурационный файл для работы с БД
$INCLUDE ${confdir}/sql.conf
# Модуль создает файл типа utmp с информацией кто и откуда в данный момент работает
radutmp {
# Путь к файлу utmp
filename = ${logdir}/radutmp
# Атрибут, из которого берем имя пользователя
username = %{User-Name}
case_sensitive = yes # Думаю, понятно
# Запрашивать информацию у NAS
check_with_nas = yes
perm = 0600 # Файл доступен только
callerid = "yes" # Записывать IP
}
}
authorize { # Модуль авторизации
sql # Использовать SQL
}
authenticate { # Модуль аутентификации
# использовать MSCHAP (запасной вариант)
Auth-Type MS-CHAP {
mschap
}
eap # Использовать EAP
}
preacct { # Предучетный модуль
# Создать уникальный идентификатор сессии перед началом учета
acct_unique
}
accounting { # Учетный модуль
# Писать соответствующую информацию файл utmp
radutmp
sql # Учет работы пользователей в БД
}
session {
# База данных сессий, используется для проверки одновременного использования
sql # Для этих целей использовать mysql
}
Единственным клиентом нашего RADIUS будет mpd, который соединяется с сервером RADIUS по локальному интерфейсу, поэтому файл clients.conf выглядит следующим образом:
client 127.0.0.1 {
secret = Super!P33a
shortname= MPD
nastype = other
}
Думаю, тут все понятно.
Переходим к конфигурированию EAP
Для работы протокола EAP-TLS нам понадобятся файлы:
- DH – файл с ключом Диффи-Хелмана;
- random – ссылка на /dev/urandom;
- root.pem – сертификат СЦ;
- server.key – закрытый ключ сервера;
- server.pem – сертификат сервера;
- ivanov_igor.p12 – PKCS#12-сертификат и закрытый ключ Игоря Иванова;
- olga_petrova.p12 – PKCS#12-сертификат и закрытый ключ Ольги Петровой;
- vladimir_sidorov.p12 – PKCS#12-сертификат и закрытый ключ Владимира Сидорова;
- PKCS#12 – это формат хранения зашифрованного закрытого ключа и сертификата в одном файле, который удобно использовать для их безопасной передачи.
Очищаем директорию /usr/local/etc/raddb/certs/ и заходим в нее:
vpn-s# rm –r /usr/local/etc/raddb/certs/*
vpn-s# cd /usr/local/etc/raddb/certs/
Создаем файл c ключем Диффи-Хельмана:
vpn-s#openssl dhparam -check -text -5 2048 -out dh
Задаем источник случайных чисел:
vpn-s# ln -s /dev/urandom /usr/local/etc/raddb/certs/random
Скрипт для создания корневого ЦС:
#!/bin/sh
# Начнем с чистого листа
rm -rf demoCA
# Создаем новый самоподписанный сертификат и закрытый ключ к нему.
# После запроса файл newreq.pem будет содержать закрытый ключ и сертификат
openssl req -new -x509 -keyout newreq.pem -out newreq.pem -days 730 -passin pass:My3ecret \
-passout pass:My3ecret -subj '/C=RU/ST=Russia/L=Moscow/O=Testco/OU=IT/CN=Testco CA/emailAddress=admin@testco.ru'
# Создаем новый центр сертификации, корневым сертификатом которого будет сертификат из файла newreq.pem
echo "newreq.pem" | CA.pl -newca >/dev/null
# Создадим файл в формате PKCS#12, используя, созданные ранее закрытый ключ и сертификат.
# Сертификат в файле demoCA/cacert.pem тот же, что и в файле newreq.pem.
# Вместо использования ключа «-in #demoCA/cacert.pem» мы могли бы использовать ключ «-in newreq.pem»
# и тогда можно было бы опустить ключ «-inkey newreq.pem», потому как файл newreq.pem содержит в себе
# и закрытый ключ и сертификат
openssl pkcs12 -export -in demoCA/cacert.pem -inkey newreq.pem -out root.p12 -cacerts -passin pass:My3ecret -passout pass:My3ecret
# Извлекаем из созданного файла в формате PKCS#12 сертификат и закрытый ключ и записываем их
# в новый файл PEM-формата root.pem
openssl pkcs12 -in root.p12 -out root.pem -passin pass:My3ecret -passout pass:My3ecret
# Зачистка
rm newreq.pem
Запускаем:
vpn-s# ./root.sh
В результате работы скрипта должны быть созданы 2 файла root.p12 и root.pem. Первый содержит закрытый ключ и сертификат СЦ в формате PKCS#12, а второй – сертификат СЦ в формате pem.
Скрипт для создания сертификата сервера RADIUS:
#!/bin/sh
# Делаем запрос на новый сертификат в формате PKCS#10
openssl req -new -newkey rsa:2048 -keyout server.key -out newreq.pem -days 730 -passin pass:My3ecret \
-passout pass:My3ecret -subj '/C=RU/ST=Russia/L=Moscow/O=Testco/OU=IT/CN=vpn-s.testco.ru/emailAddress=admin@testco.ru'
# Подписываем запрос на сертификат. Ключ -infiles указывает на запрос созданный предыдущей командой,
# вывод идет в файл #newcert.pem. Ключ -extensions необходим для добавления OID-проверки подлинности сервера
openssl ca -policy policy_anything -out server.crt -passin pass:My3ecret -key My3ecret –extensions xpserver_ext -extfile xpextensions -infiles newreq.pem
# Зачистка
rm newreq.pem
Запускаем:
vpn-s# ./server.sh
В результате работы скрипта должны быть созданы 2 файла server.key и server.crt, которые содержат закрытый ключ и сертификат сервера соответственно.
Скрипт для создания клиентского сертификата (на примере создания для сертификата Игоря Иванова):
#!/bin/sh
# Делаем запрос на новый сертификат в формате PKCS#10
openssl req -new -keyout newreq.pem -out newreq.pem -days 730 -passin pass:My3ecret -passout pass:My3ecret \
-subj '/C=RU/ST=Russia/L=Moscow/O=Testco/OU=IT/CN=Igor Ivanov/emailAddress=ivanov.i@testco.ru'
# Подписываем запрос на сертификат
# Ключ -infiles указывает на запрос созданный предыдущей командой, вывод идет в файл newcert.pem.
# Ключ -extensions необходим для добавления OID-проверки подлинности сервера
openssl ca -policy policy_anything -out newcert.pem –passin pass:My3ecret -key My3ecret --extensions xpclient_ext -extfile xpextensions -infiles newreq.pem
# Создадим файл cert-srv.p12 формата PKCS#12 из находящихся в файле newreq.pem,
# нового сертификата и его закрытого ключа
openssl pkcs12 -export -in newcert.pem -inkey newreq.pem –out ivanov_igor.p12 -clcerts -passin pass:My3ecret -passout pass:My3ecret
# Зачистка
rm newcert.pem newreq.pem
Запускаем:
vpn-s# ./client.sh
В результате работы скрипта мы получили файл PKCS#12, который содержит закрытый ключ и сертификат Игоря Иванова, аналогичным образом создадим сертификаты для оставшихся двух пользователей.
Далее создадим конфигурационный файл для EAP.
Файл eap.conf:
# Расширяемый Протокол Аутентификации
#
# Для всех видов EAP-аутентификации
eap {
# Какой тип EAP-аутентификации применить, когда получен EAP-идентификатор
default_eap_type = tls
# Таймер по умолчанию для очистки списка EAP
# Он служит для сопоставления полученных EAP-ответов с отправленными EAP-запросами
timer_expire = 60
# Поддерживаемые типы EAP
# md5 {
# }
# Секция EAP-TLS
tls {
private_key_password = whatever
private_key_file = /usr/local/etc/raddb/certs/server.key
# Иногда закрытый ключ и сертификат расположены в одном файле, тогда директивы private_key_file
# и certificate_file должны иметь одно и то же значение
certificate_file = /usr/local/etc/raddb/certs/server.pem
# Список корневых центров сертификации
CA_file = /usr/local/etc/raddb/certs/root.pem
# Файлы, необходимые для работы протокола TLS
dh_file = /usr/local/etc/raddb/certs/DH
random_file = /dev/urandom
# Это значение никогда не должно превышать MAX_RADIUS_LEN (4096), предпочтительно должно
# составлять половину значения MAX_RADIUS_LEN, для того чтобы другие атрибуты
# могли поместиться в радиус-пакет. На большинстве точек доступа значение максимальной
# длины пакета сконфигурировано между 1500-1600. В таком случае, размер фрагмента
# должен быть <=1024
fragment_size = 1024
# include_length – это флаг, который по умолчанию установлен в значение «да». Если он установлен
# в значение «да», общая длина сообщения включается в каждый отправляемый пакет. Если он установлен
# в значение «нет», полная длина сообщения включается только в первый пакет серии фрагментов
include_length = yes
# В данном случае нет необходимости делать проверку по спискам отозванных сертификатов, потому что
# удалить пользователя из базы проще, чем генерировать новый crl
#check_crl = no
}
}
Далее нужно предоставить серверу RADIUS данные, необходимые для работы с БД. Для этого нам понадобится создать файл sql.conf, содержимое которого следует ниже:
sql {
driver = "rlm_sql_mysql" # Тип SQL-базы MySQL
# Имя хоста или IP-адрес сервера MySQL, в нашем случае это localhost
server = "localhost"
# Логин пользователя MySQL созданного специально для работы с базой RADIUS
login = "freeradius"
password = "d1ametR" # Eго пароль
radius_db = "radius" # Название базы
acct_table1 = "radacct" # Первая таблица учета
acct_table2 = "radacct" # Вторая таблица учета
# Таблица проверяемых атрибутов
authcheck_table = "radcheck"
# Таблица выдаваемых атрибутов
authreply_table = "radreply"
# Таблица проверяемых атрибутов для групп
groupcheck_table = "radgroupcheck"
# Таблица выдаваемых атрибутов для групп
groupreply_table = "radgroupreply"
# Таблица соответствия пользователей и групп
usergroup_table = "usergroup"
# Удалять подвисшие сессии
deletestalesessions = "yes"
sqltrace = "no" # Не писать в файл SQL-запросы
sqltracefile = "${logdir}/sqltrace.sql"
# Количество одновременно открытых SQL-соединений
num_sql_socks = 5
# Задержка перед повторной попыткой, после неудачного соединения
connect_failure_retry_delay = 60
# Получить значение атрибута %{SQL-User-Name} из атрибута %{User-Name}
sql_user_name = "%{User-Name}"
# Проверка атрибутов во время авторизации
authorize_check_query = "SELECT id, UserName, Attribute, Value, op FROM ${authcheck_table} \
WHERE Username = '%{SQL-User-Name}' ORDER BY id"
# Выдача атрибутов во время авторизации
authorize_reply_query = "SELECT id, UserName, Attribute, Value, op FROM ${authreply_table} \
WHERE Username = '%{SQL-User-Name}' ORDER BY id"
# Проверка атрибутов для групп во время авторизации
authorize_group_check_query = "SELECT ${groupcheck_table}.id, ${groupcheck_table}.GroupName, \
${groupcheck_table}.Attribute, ${groupcheck_table}.Value, ${groupcheck_table}.op \
FROM ${groupcheck_table}, ${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName ORDER BY ${groupcheck_table}.id"
# Выдача атрибутов для групп во время авторизации
authorize_group_reply_query = "SELECT ${groupreply_table}.id, ${groupreply_table}.GroupName, \
${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.op \
FROM ${groupreply_table}, ${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName ORDER BY ${groupreply_table}.id"
# Запрос управления учетом
accounting_onoff_query = "UPDATE ${acct_table1} SET AcctStopTime='%S', \
AcctSessionTime=unix_timestamp('%S') - unix_timestamp(AcctStartTime), \
AcctTerminateCause= '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time}' \
WHERE AcctSessionTime=0 AND AcctStopTime=0 AND NASIPAddress= '%{NAS-IP-Address}' AND AcctStartTime <= '%S'"
# Запрос обновления данных учета
accounting_update_query = "UPDATE ${acct_table1} SET FramedIPAddress = '%{Framed-IP-Address}', \
AcctSessionTime = '%{Acct-Session-Time}', AcctInputOctets = '%{Acct-Input-Octets}', \
AcctOutputOctets = '%{Acct-Output-Octets}' WHERE AcctSessionId = '%{Acct-Session-Id}' \
AND UserName = '%{SQL-User-Name}' AND NASIPAddress= '%{NAS-IP-Address}'"
# Запрос начала учета
accounting_start_query = "INSERT into ${acct_table1} (AcctSessionId, AcctUniqueId, UserName, Realm, \
NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, AcctSessionTime, AcctAuthentic, \
ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, \
AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay) \
values('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', \
'%{NAS-Port}', '%{NAS-Port-Type}', '%S', '0', '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', \
'%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', \
'%{Framed-IP-Address}', '%{Acct-Delay-Time}', '0')"
# Запрос окончания учета
accounting_stop_query = "UPDATE ${acct_table2} SET AcctStopTime = '%S', AcctSessionTime = '%{Acct-Session-Time}', \
AcctInputOctets = '%{Acct-Input-Octets}', AcctOutputOctets = '%{Acct-Output-Octets}', \
AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time}', \
ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' \
AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}'"
# Проверка одновременных соединений
simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, \
CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime = 0"
# Запрос информации о членстве пользователей в группах
group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}'"
}
Для работы сервера RADIUS необходим словарь атрибутов. Мы будем использовать словарь из дистрибутива FreeRADIUS с дополнением специфических атрибутов mpd. Скопируем словарь из дистрибутива:
vpn-s# cp /usr/local/etc/raddb/dictionary.sample /usr/local/etc/raddb/dictionary
и добавим в него следующую строку:
$INCLUDE /usr/local/share/freeradius/dictionary.mpd
затем создадим файл-словарь /usr/local/share/freeradius/dictionary.mpd:
#----------------------------------------------------------
# dictionary.mpd
VENDOR mpd 12341
ATTRIBUTE mpd-rule 1 string mpd
ATTRIBUTE mpd-pipe 2 string mpd
ATTRIBUTE mpd-queue 3 string mpd
#----------------------------------------------------------
Копируем оставшиеся необходимые файлы:
vpn-s# cp /usr/local/etc/raddb/huntgroups.sample /usr/local/etc/raddb/huntgroups
vpn-s# /usr/local/etc/raddb/hints.sample /usr/local/etc/raddb/hints
Конфигурация базы данных и создание учетных записей
В заключение нам необходимо установить сервер MySQL для хранения данных авторизации пользователей и учета их работы с VPN:
vpn-s# cd /usr/ports/databases/mysql50-server
vpn-s# make install clean
vpn-s# echo 'mysql_enable="YES"' >> /etc/rc.conf
Создадим базу данных:
vpn-s# mysql
mysql> CREATE DATABASE radius;
mysql> use radius
mysql> SOURCE /usr/local/share/doc/freeradius/examples/mysql.sql
Далее необходимо завести пользователя Freeradius в MySQL с полными правами на базу radius:
mysql> GRANT ALL PRIVILEGES ON radius.* to 'freeradius'@'localhost' IDENTIFIED BY 'd1ametR';
mysql> FLUSH PRIVILEGES;
mysql>exit
База готова, начнем ее заполнять.
Создадим в базе данных трех пользователей: Igor Ivanov, Olga Petrova, Vladimir Sidorov, которые будут являться членами групп: RDP_USERS, HTTP_USERS, ICA_USERS соответственно:
vpn-s# mysql –e ‘ INSERT INTO usergroup (UserName, GroupName, priority) VALUES ("Igor Ivanov", " RDP_USERS",1)’ radius
vpn-s# mysql –e ‘ INSERT INTO usergroup (UserName, GroupName, priority) VALUES ("Olga Petrova", " HTTP_USERS",1)’ radius
vpn-s# mysql –e ‘ INSERT INTO usergroup (UserName, GroupName, priority) VALUES ("Vladimir Sidorov", " ICA_USERS",1)’ radius
Установим для групп протокол авторизации EAP:
vpn-s# mysql –e ‘INSERT INTO radgroupcheck (id, GroupName, Attribute, op, Value) VALUES (10, "RDP_USERS", "Auth-Type", ":=", "EAP")’ radius
vpn-s# mysql –e ‘INSERT INTO radgroupcheck (id, GroupName, Attribute, op, Value) VALUES (20, "HTTP_USERS", "Auth-Type", ":=", "EAP") ’ radius
vpn-s# mysql –e ‘INSERT INTO radgroupcheck (id, GroupName, Attribute, op, Value) VALUES (30, "ICA_USERS", "Auth-Type", ":=", "EAP") ’ radius
Определим списки доступа для каждой из групп:
vpn-s# mysql –e ‘INSERT INTO radgroupreply (id, GroupName, Attribute, op, Value) \
VALUES (10, "RDP_USERS", "mpd-rule","+="," 100=allow tcp from any to 192.168.0.10/24 3389 keep-state")’ radius
vpn-s# mysql –e ‘INSERT INTO radgroupreply (id, GroupName, Attribute, op, Value) \
VALUES (20, "HTTP_USERS", "mpd-rule","+="," 100=allow tcp from any to 192.168.0.11/24 80,443 keep-state")’ radius
vpn-s# mysql –e ‘INSERT INTO radgroupreply (id, GroupName, Attribute, op, Value) \
VALUES (30, "RDP_USERS", "mpd-rule","+="," 100=allow tcp from any to 192.168.0.0/24{12-15} 1494 keep-state")’ radius
Конфигурация клиента
Прежде чем настраивать VPN-соединение в Windows, следует записать закрытый ключ и сертификат клиента в хранилище электронного ключа e-token (предполагается, что драйвер e-token уже установлен).
Запускаем утилиту «Свойства e-token» и выбираем вкладку дополнительно, вводим ПИН-код.
Выбираем вкладку «Сертификаты и ключи» и кликаем импортировать сертификат, выбираем файл PKCS#12 и вводим пароль, который был установлен при создании файла PKCS#12:
Если пароль был введен правильно, мы можем видеть данные об импортированном сертификате (см. рис. 3).
Рисунок 3. Сертификат Игоря Иванова в утилите «Свойства e-token»
Таким образом, мы инициализируем три ключа e-token, по одному для каждого из наших пользователей. После этого необходимо импортировать на клиентскую машину в раздел доверенных корневых центров сертификации компьютера сертификат ЦC из файла root.pem, предварительно изменив его расширение на «.crt».
Настройка VPN-соединения:
- Создадим новое VPN-соединение с названием «testco», имя VPN-сервера vpn-s.testco.ru.
- Далее открываем свойства вновь созданного соединения (см. рис. 4).
- Выбираем вкладку «Безопасность» и в ней пункт «Дополнительные (выборочные) параметры». Нажимаем кнопку «Параметры». Появится окно дополнительных параметров безопасности.
- В разделе «Шифрование данных» кликаем мышкой на обязательное шифрование данных. В разделе «Безопасный вход» «Протокол расширенной проверки подлинности (EAP)», заходим в его свойства (см. рис .5).
- Отмечаем пункт «Использовать мою смарт-карту». Ставим галочку «проверка сертификата сервера» и галочку «подключение к серверам». Вписываем имя vpn-s.testco.ru. Выбираем доверенный корневой центр сертификации «Testco CA». Далее жмем кнопку «ОК» 3 раза (см. рис. 6).
- Теперь можно щелкнуть мышкой на появившемся на рабочем столе ярлыке «testco» и подключиться к сети Testco.
- При подключении вам необходимо ввести ПИН-код e-token, который был установлен при его инициализации.
Рисунок 4. Свойства VPN-соединения testco
Рисунок 5. Настройка дополнительных параметров безопасности
Рисунок 6. Настройка параметров протокола EAP-TLS
Теперь, если все настройки выполнены без ошибок, подключившись к VPN с помощью любого из ключей, мы получаем доступ к ресурсам локальной сети компании согласно приведенной выше схеме доступа.
В случае возникновения проблем соединения советую включать отладку MPD в файле mpd.conf:
startup:
log +radius2 +ipcp2 +iface2
и запускать radiusd с ключом -X.
Сравнение с альтернативными решениями
Попробуем сравнить наше решение с другими VPN-решениями, которые используются для организации безопасного удаленного доступа клиентов в локальную сеть организации. Наиболее популярной технологией, используемой в коммерческих решениях VPN, является IPsec. Она обеспечивает самый высокий уровень безопасности VPN, однако, на мой взгляд, больше подходит для организации шифрованных туннелей через Интернет именно между сетями, так как возникают трудности при подключении клиентов из-за NAT (NAT-T все еще сырая технология). Даже при нормальной работе NAT-T в том случае, если мы используем для аутентификации SSL-сертификаты, которые из-за размера не могут быть переданы в одном пакете, существует проблема фрагментации пакетов IKE (протокол обмена ключами и согласования параметров в IPSec). При этом не все пакетные фильтры и трансляторы сетевых адресов на маршруте от клиента до VPN-шлюза будут корректно работать с фрагментированными пакетами и пропускать их. И если фрагментированный пакет не дойдет до места назначения, параметры безопасности IPsec не будут установлены, подключение к VPN не состоится.
Ради справедливости хочу заметить, что при использовании PPTP тоже могут возникнуть проблемы с NAT, если NAT не умеет анализировать поле Call ID в пакетах GRE. Эти проблемы решаются с помощью дополнительных «подсистем», как например conntrack в Linux, однако надо помнить, что шлюзы, через которые будут выходить в Интернет ваши клиенты, не находятся под вашим контролем, следовательно, далеко не всегда вы сможете решать подобного рода проблемы. Один из вариантов решения такой проблемы это покупка прямого IP-адреса.
Что касается другой популярной технологии, OpenVPN, то это решение лишено недостатков как PPTP, так и IPsec. Для шифрования и аутентификации в OpenVPN используется протокол SSL (TLS), о преимуществах которого я упоминал при описании EAP-TLS; отсутствуют проблемы совместимости с NAT; серверное и клиентское ПО распространяется под лицензией GPL.
Однако Microsoft не использует эту технологию, и никто не может гарантировать, что в следующем сервисном пакете для XP или в Windows Vista не будут содержаться такие исправления или новшества, после которых OpenVPN перестанет работать. А ведь такое уже было после выхода SP2 для XP.
Еще один недостаток OpenVPN по сравнению с PPTP – это необходимость установки дополнительного клиентского ПО и отсутствие его автоматического обновления. Притом что в OpenVPN часто находят уязвимости, а пользователи обычно не любят обновлять ПО, это существенный минус.
Мое мнение, что OpenVPN – это наиболее перспективный проект в своей области, но для использования в корпоративной среде, где подавляющее большинство клиентских машин работает под управлением Windows, он не подходит.
Заключение
Я считаю, что в итоге нам удалось создать VPN с относительно высоким уровнем безопасности, несмотря на то что создатели протокола PPTP сделали это почти невозможным. Если бы не возможность использования аутентификации EAP-TLS, протокол можно было бы смело хоронить, а с таким доспехом «старый уродец» еще послужит нам. Конечно, такие проблемы, как атаки на шифр RC4, отсутствие шифрования во время установки PPP-соединения и отсутствие аутентификации GRE-пакетов, остались, но мы перекрыли возможность для проведения наиболее опасных атак, результатом которых может быть проникновение злоумышленника во внутреннюю сеть компании или раскрытие информации, передаваемой по VPN. Ведь любой грамотный в области информационной безопасности специалист прекрасно понимает, что взломать можно любую систему, вопрос только в том, какое количество ресурсов будет потрачено на этот взлом. И наша задача заключается в том, чтобы цена взлома оказалась непосильно дорогой для злоумышленников. Пусть ищут другие способы добычи информации, на нашем участке обороны им ничего не светит.
Выражаю благодарность всем, кто начинал и продолжает работу над проектом MPD, особенно Антону Мотину и Глебу Смирнову, благодаря которым недавно вышел первый стабильный релиз этого замечательного ПО.
- http://www.schneier.com/paper-pptp.html.
- http://www.schneier.com/paper-pptpv2.html.
- http://asleap.sourceforge.net.
- http://www3.ietf.org/proceedings/99jul/I-D/draft-ietf-pppext-mppe-keys-00.txt.
- http://www.sans.org/resources/malwarefaq/pptp-vpn.php.
- http://www.freeradius.org/doc/EAPTLS.pdf.
- http://www.ietf.org/rfc/rfc3715.txt.
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|