Межсетевые экраны (FireWall), демилитаризованная зона (DMZ), трансляция сетевых адресов (NAT, Masquerade)

Для устранения проблем, связанных с безопасностью, было разработано много различных решений, самым известным и распространенным из которых является применение межсетевых экранов (firewall). Их использование - это первый шаг, который должна сделать любая организация, подключающая свою корпоративную сеть к Internet. Первый, но далеко не последний. Одним межсетевым экраном для построения надежного и защищенного соединения с Internet не обойтись. Необходимо реализовать целый ряд технических и организационных мер, чтобы обеспечить приемлемый уровень защищенности корпоративных ресурсов от несанкционированного доступа.

Межсетевые экраны реализуют механизмы контроля доступа из внешней сети к внутренней путем фильтрации всего входящего и исходящего трафика, пропуская только авторизованные данные. Все межсетевые экраны функционируют на основе информации, получаемой от различных уровней эталонной модели ISO/OSI, и чем выше уровень OSI, на основе которого построен межсетевой экран, тем выше уровень защиты, им обеспечиваемый. Существует три основных типа межсетевых экранов - пакетный фильтр (packet filtering), шлюз на сеансовом уровне (circuit-level gateway) и шлюз на прикладном уровне (application-level gateway). Очень немногие существующие межсетевые экраны могут быть однозначно отнесены к одному из названных типов. Как правило, МСЭ совмещает в себе функции двух или трех типов.

При формировании DMZ создается две физически разделенные сети: одна — для общедоступных серверов, другая — для внутренних серверов и рабочих станций. В зависимости от типа DMZ и числа используемых брандмауэров, применяется та или иная политика маршрутизации для каждой из сетей и жестко контролируется доступ между:

Главное преимущество использования DMZ вместо простого брандмауэра состоит в том, что при атаке на общедоступный сервер риск компрометации внутренних серверов снижается, поскольку общедоступные и внутренние серверы отделены друг от друга. Если скомпрометированный сервер находится в DMZ, злоумышленник не сможет напрямую атаковать другие, более важные серверы, расположенные во внутренней сети. Брандмауэр блокирует любые попытки компьютеров из DMZ подсоединиться к компьютерам внутренней сети, за исключением специально разрешенных соединений.

Любой сети, желающей подключиться к Интернет, необходим набор IP адресов, которые может выделить любая имеющая на это право организация. Существуют три класса IP адресов: класс А, внутри которого можно описать до 16777214 хостов, класс В, позволяющий описать до 65533 хостов и класс С с 254 хостами.

Бум, который переживает Интернет в последние годы, привел к тому, что сети класса А и В в настоящее время стали недоступны для организаций и отдельных пользователей. Поэтому Вам может быть выделена только сеть класса С, с 254 адресами. При большем числе хостов вам потребуются другие сети класса С, что усложняет работу администратора. Другой способ решения проблемы состоит в использовании трансляции сетевых адресов (NAT).

Трансляция сетевых адресов - это технология, которая позволяет использовать для внутренней сети любые адреса, возможно даже из класса А; при этом сохраняется одновременный и прозрачный доступ в Интернет для всех хостов.
Механизм функционирования такого процесса достаточно прост: каждый раз, когда хост с зарезервированным адресом пытается получить доступ в Интернет, межсетевой экран контролирует эту попытку и автоматически преобразует его адрес в разрешенный. Когда хост назначения отвечает и посылает данные на разрешенный адрес, межсетевой экран преобразует его обратно в зарезервированный адрес и передает данные внутреннему хосту. При этом ни клиент, ни сервер не знают о существовании этого преобразования.

IP Masquerade - вариант прокси-сервера. С помощью IP Masquerade можно организовать подключение к Internet машин в локальной сети через один IP-адрес.

IP Masquerade - это, также, хорошее средство защиты сети, так как все машины, кроме gateway, не видны из Интернет.

С помощью IP Masquerade мы закрываем все компьютеры в локальной сети (кроме серверов) от атак извне (другими словами, мы их делаем невидимыми, задав им "несуществующие" адреса и подменяя их на адрес данной машины).

Программирование сокетов

Для обеспечения сетевых коммуникаций используются сокеты. Сокет это конечная точка сетевых коммуникаций. Каждый использующийся сокет имеет тип и ассоциированный с ним процесс. Сокеты существуют внутри коммуникационных доменов. Домены это абстракции, которые подразумевают конкретную структуру адресации и множество протоколов, которое определяет различные типы сокетов внутри домена.

В Internet домене сокет - это комбинация IP адреса и номера порта, которая однозначно определяет отдельный сетевой процесс во всей глобальной сети Internet. Два сокета, один для хоста-получателя, другой для хоста-отправителя, определяют соединение для протоколов, ориентированных на установление связи, таких, как TCP.

Создание сокета

Для создания сокета используется системный вызов socket.

s = socket(domain, type, protocol);

Этот вызов основывается на информации о коммуникационном домене и типе сокета. Для использования особенностей Internet, значения параметров должны быть следующими:

communication domain -

AF_INET (Internet протоколы).

type of the socket -

SOCK_STREAM; Этот тип обеспечивает последовательный, надежный, ориентированный на установление двусторонней связи поток байтов.

Выше был упомянут сокет с типом stream. Краткое описание других типов сокетов приведено ниже:

Datagram socket -

поддерживает двусторонний поток данных. Не гарантируется, что этот поток будет последовательным, надежным, и что данные не будут дублироваться. Важной характеристикой данного сокета является то, что границы записи данных предопределены.

Raw socket -

обеспечивает возможность пользовательского доступа к низлежащим коммуникационным протоколам, поддерживающим сокет-абстракции. Такие сокеты обычно являются датаграм- ориентированными.

Функция socket создает конечную точку для коммуникаций и возвращает файловый дескриптор, ссылающийся на сокет, или -1 в случае ошибки. Данный дескриптор используется в дальнейшем для установления связи.

Для создания сокета типа stream с протоколом TCP, обеспечивающим коммуникационную поддержку, вызов функции socket должен быть следующим:

s = socket(AF_INET, SOCK_STREAM, 0);

Привязка к локальным именам

Сокет создается без имени. Пока с сокетом не будет связано имя, удаленные процессы не имеют возможности ссылаться на него и, следовательно, на данном сокете не может быть получено никаких сообщений. Коммуникационные процессы используют для данных целей ассоциации. В Internet домене ассоциация складывается из локального и удаленного адреса и из локального и удаленного порта. В большинстве доменов ассоциация должна быть уникальной.

В Internet домене связывание сокета и имени может быть весьма сложным, но, к счастью, обычно нет необходимости специально привязывать адрес и номер порта к сокету, так как функции connect и send автоматически свяжут данный сокет с подходящим адресом, если это не было сделано до их вызова.

Для связывания сокета с адресом и номером порта используют системный вызов bind:

bind(s, name, namelen);

Привязываемое имя (name) это строка байт переменной длины, которая интерпретируется поддерживаемым протоколом. Интерпретация может различаться в различных коммуникационных доменах.

Когда сервер желает предложить один из своих сервисов, он связывает сокет с общеизвестным адресом, ассоциирующимся с данным сервисом, и пассивно слушает этот сокет. Для этих целей используется системный вызов listen:

error = listen(s, qlength);

где s это дескриптор сокета, а qlength это максимальное количество запросов на установление связи, которые могут стоять в очереди, ожидая обработки сервером; это количество может быть ограничено особенностями системы.

Когда сервер получает запрос от клиента и принимает решение об установлении связи, он создает новый сокет и связывает его с ассоциацией, эквивалентной 'слушающему сокету'. Для Internet домена это означает тот же самый номер порта. Для этой цели используется системный вызов accept:

newsock = accept(s, clientaddr, clientaddrlen);

Сокет, ассоциированный клиентом, и сокет, который был возвращен функцией accept, используются для установления связи между сервером и клиентом.

Передача данных

Когда связь установлена, с помощью различных функций может начаться процесс передачи данных. При наличии связи, пользователь может посылать и получать сообщения с помощью функций read и write:

write(s, buf, sizeof(buf)); read(s, buf, sizeof(buf));

Вызовы send и recv практически идентичны read и write, за исключением того, что добавляется аргумент флагов.

send(s, buf, sizeof(buf), flags); recv(s, buf, sizeof(buf), flags);

Могут быть указаны один или более флагов с помощью ненулевых значений, таких, как следующие:

  • MSG_OOB - Посылать/получать данные, характерные для сокетов типа stream.
  • MSG_PEEK - Просматривать данные без чтения. когда указывается в recv, любые присутствующие данные возвращаются пользователю, но сами данные остаются как "непрочитанные". Следующий read или recv вызванный на данном сокете вернет прочитанные в прошлый раз данные.
  • MSG_DONTROUTE - посылать данные без маршрутизации пакетов. (Используется только процессами, управляющими таблицами маршрутизации.)

Закрывание сокетов

Когда взаимодействующие модули решают прекратить передачу данных и закрыть сеанс связи, они обмениваются трехсторонним рукопожатием с сегментами, содержащими установленный бит "От отправителя больше нет данных" (этот бит еще называется FIN бит).

Если сокет больше не используется, процесс может закрыть его с помощью функции close, вызвав ее с соответствующим дескриптором сокета:

close(s);

Если данные были ассоциированы с сокетом, обещающим доставку (сокет типа stream), система будет пытаться осуществить передачу этих данных. Тем не менее, по истечении довольно таки длительного промежутка времени, если данные все еще не доставлены, они будут отброшены. Если пользовательский процесс желает прекратить любую передачу данных, он может сделать это с помощью вызова shutdown на данном сокете для его закрытия. Вызов shutdown вызывает "моментальное" отбрасывание всех стоящих в очереди данных. Формат вызова следующий:

shutdown(s, how);

где how имеет одно из следующих значений:

  • 0 - если пользователь больше не желает читать данные
  • 1 - если данные больше не будут посылаться
  • 2 - если данные не будут ни посылаться ни получаться

Установление связи

Со стороны клиента связь устанавливается с помощью стандартной функции connect:

error = connect(s, serveraddr, serveraddrlen);

которая инициирует установление связи на сокете, используя дескриптор сокета s и информацию из структуры serveraddr, имеющей тип sockaddr_in, которая содержит адрес сервера и номер порта на который надо установить связь. Если сокет не был связан с адресом, connect автоматически вызовет системную функцию bind.

Connect возвращает 0, если вызов прошел успешно. Возвращенная величина -1 указывает на то, что в процессе установления связи произошла некая ошибка. В случае успешного вызова функции процесс может работать с дескриптором сокета, используя функции read и write, и закрывать канал используя функцию close.

Ниже представлена последовательность действий для создания сервера

 
Socket() Создать сокет
Bind() Связать сокет с локальным адресом
 
Listen() Перевести сокет в режим ожидания входящих соединений
Accept() Принять(разрешить) входящее соединение.
 
Send() Receive() Принимать и передавать данные по открытому соединению (обмениваться данными с тем, кто присоединился)    
 
Close Закрыть соединение

И по созданию клиента:

 
Socket() Создать сокет
Bind() Связать сокет с локальным адресом
 
Connect() Подключиться к определенному удаленным узлу (указав по какому порту )  
 
Send() Receive() Принимать и передавать данные по открытому соединению (обмениваться данными с тем, к кому присоединились)  
 
Сlose() Закрыть соединение

Наши рекомендации