курсовая приближенно по серверам. Удаленные программные средства первичной
Скачать 2.16 Mb.
|
2.4.3 Защита данных при передаче сообщений Защита данных необходима для любой важной и/или конфиденциальной информации, передаваемой по общедоступной сети. Обеспечение стойкого шифрования передаваемых от прикладных систем данных необходимо, так как прокладка отдельной сети и организация инфраструктуры для мониторинга удаленных объектов может оказаться слишком дорогостоящей и просто неразумной, если на объекте уже имеется существующее подключение к корпоративной сети или сети Интернет. Одним из таких протоколов защиты информации является протокол TLS – криптографический протокол, использующий ассимметричную криптографию для аутентификации, симметричное шифрование для конфиденциальности и коды аутентичности сообщений для сохранения целостности сообщений. TLS основан на предшествующем ему протоколе SSL 3.0, который в данный момент считается устаревшим. Кроме того против SSL 3.0 существуют атаки, позволяющие захватить канал передачи информации за короткое время (например, атака POODLE [10]). Данный протокол включает в себя три основных стадии: фаза переговоров, подключение общего ключа и подтверждение начала 31 зашифрованного соединения. Фаза переговоров является первой фазой установления соединения, во время которой клиент и сервер договариваются о используемой версии протокола, обмениваются своими публичными ключами (цифровыми сертификатами) и генерируют общий секретный ключ для текущей сессии. Далее клиент посылает пакет ChangeCipherSpec, который обозначает вторую фазу установки соединения, начиная с которой обмен информацией производится по зашифрованному каналу. Клиент посылает сообщение, содержащее свой MAC-адрес и хэш, сгенерированный на основе предыдущих сообщений. Если серверу не удается расшифровать сообщение, то соединение прерывается. В ином случае сервер отвечает пакетом ChangeCipherSpec и пакетом Finished, после которого начинается обмен данными с помощью протоколов более высокого уровня. В разрабатываемом проекте используется протокол TLS 1.2 как наиболее современный и безопасный на момент написания. Так как не все наблюдаемые прикладные системы имеют достаточно вычислительных мощностей для поддержки шифрованного соединения, то передача данных открытым текстом поддерживается наряду с безопасным каналом. Такая поддержка возможна благодаря особенностям алгоритма TLS, который позволяет не только создавать защищенные соединения, но и шифровать уже существующие. Для этого клиент должен отправить команду, обозначающую запрос на начало шифрования серверу. Команда определяется протоколом прикладной программы, в данном случае – протоколом сообщения между API и сервером обработки сообщений. Так как команда на начало шифрования может быть перехвачена и подавлена между прикладной системой и сервером, то на сервере должна быть настраиваемая опция, определяющая, разрешено ли принимать и обрабатывать незащищенные соединения. В случае установленного запрета первое входящее сообщение отбрасывается, а соединение закрывается. 32 В случае сбоя некоторые виды подсистем могут отправлять тысячи ошибок в секунду, тем самым серьезно нагружая сервер обработки сообщений. При отказе нескольких таких систем нагрузка переходит и на сервер журнализации, что может повлечь за собой его сбой. Так как сервер журнализации необходим для наблюдения за работой системы, то для сервера нужно разработать механизм, который будет агрегировать похожие сообщения и отправлять лишь одно сообщение из группы с указанием количества принятых событий. Одним из таких механизмов является алгоритм текущего ведра (англ. Leaky Bucket). Схематическое описание данного алгоритма изображено на рисунке 8. Рисунок 8 – Схематическое объяснение алгоритма текущего ведра Текущее ведро получает поток данных на входе и ограничивает его количество на выходе путем отбрасывания излишков. Фактически, текущее ведро является конечной FIFO-очередью ограниченного размера [11], причем при попытке добавления объекта в конец заполненной очереди объект отбрасывается. Для снижения нагрузки с сервера и сохранения всех сообщений достаточно создавать короткоживущую очередь для каждого полученного сообщения с уникальными данными, сохранять количество отброшенных сообщений и отправлять его вместе с самим сообщением, для которого были получены дубликаты. Таким образом, в случае получения большого количества сообщений за короткое время на сервер журнализации отправятся первые несколько из них (точное количество зависит от 33 реализации алгоритма и настроек очереди) и финальное сообщение, указывающее количество повторений. 2.5 Взаимодействие с серверными программными средствами платформы журнализации На стороне сервера журнализации в БД были созданы классы cо специальными методами валидации и хэш-массивом данных для сохранения сообщений. Были рассмотрены различные способы взаимодействия с СУБД Cache [12], однако, для упрощения работы с БД было принято решение использовать утилиту Cache Managed Provider for .NET и сгенерированные ей классы языка C#. Данная утилита предназначена для получения описания классов из БД Cache и генерации прокси-классов на языке C# или Visual Basic .NET согласно описанию. Такие прокси-классы позволяют работать с классами БД как с обычными классами языка C#. С их помощью Cache Managed Provider for .NET абстрагирует взаимодействие с БД и обеспечивает статическую проверку типов данных (т.е. проверку во время компиляции). Это дает дополнительную защиту от ошибок, связанных со стандартной генерацией SQL-запросов для баз данных. Фактически, подход данной утилиты является аналогом ORM-систем (англ. Object-Relational Mapping, объектно- реляционное отображение) для реляционных баз данных. Использование данной технологии позволяет ускроить разработку приложений. Для использования утилиты необходимо предварительно описать целевой класс на сервере журнализации, сгенерировать файл прокси-класса с помощью утилиты и подключить его к проекту. Возможна работа с удаленным сервером журнализации, так как для соединения с базой используется подключение по сети. Подключение создается в момент создания класса соединения с базой данных. 34 При использовании данной утилиты было создано подключение к платформе журнализации EventPlatform и получены описания классов, которые были сконвертированы в классы C#. В данной работе используется описание универсального класса журнализации ActualEvent, используемого в составе системы журнализации EventPlatform. Было принято решение использовать локальный файл настроек вместо стандартного хранения настроек серверов в реестре, так как при задаче копирования конфигурации на множество ЭВМ для создания кластера серверов копировать конфигурацию из реестра сложнее, чем из обычного файла. Для удобства конфигурации было решено использовать локальный XML-файл для хранения текущей конфигурации сервера. XML (англ. eXtensible Markup Language – расширяемый язык разметки) – язык разметки, созданный и рекомендованный консорциумом W3C (Консорциум Всемирной паутины). Как и HTML, XML базируется на SGML – Standard Generalized Markup Language (Стандартный Обобщенный Язык Разметки). XML разрабатывался как язык с простым формальным синтаксисом, удобный для создания и обработки документов программами и одновременно удобный для чтения и создания документов человеком, с подчеркиванием нацеленности на использование в Интернете. Язык называется расширяемым, поскольку он не фиксирует разметку, используемую в документах: разработчик волен создать разметку в соответствии с потребностями к конкретной области, будучи ограниченным лишь синтаксическими правилами языка. Формат XML был выбран, как наиболее подходящий и удобный для хранения фиксированного набора настроек. Также данный выбор облегчит разработку механизмов удаленного развертывания сервера благодаря развитой поддержке XML-разметки в СУБД Cache. 35 Файл конфигурации данных может либо заполняться вручную администратором сервера, либо редактироваться и сохраняться с помощью интерфейса сервера. При запуске сервер будет считывать и десериализировать файл настроек в класс, хранящий текущие настройки в виде объектов языка C#. При конфигурации сервера через пользовательский интерфейс возможна обратная сериализация объекта и запись его в файл в сериализованном виде для сохранения настроек для последующих запусков. Локальный файл конфигурации обновляется при каждом запуске сервера обработки сообщений в том случае, если удалось установить соединение с БД метаданных, где храниться актуальная версия конфигурации. Файл конфигурации хранит следующие параметры: ー номер порта сервера обработки сообщений; ー строка соединения с БД журнала событий; ー список данных о компонентах ПС, работающих в режиме push. Строка соединения с БД содержит адрес и порт сервера БД, название пространства имен, в котором расположена БД, идентификатор пользователя и пароль для получения доступа к БД. Данные о компонентах ПС включают в себя следующие составляющие: ー идентификатор; ー IP-адрес и номер; ー TCP-порта компонента ПС. После чтения конфигурации сервер обработки сообщений устанавливает соединение с БД журнала cсобытий и производит отправку сообщений. В том случае, если соединение установить невозможно, принятые от компонентов прикладных систем сообщения записываются в локальный файл конфигурации сервера обработки сообщений (рисунок 9). 36 Рисунок 9 – Диаграмма последовательности «Взаимодействия с серверными программными средствами» Сформированный лог-файл будет отправлен в БД журнала при следующем успешном соединении и после успешной отправки будет очищен. 37 3 Разработка программных средств сервера сообщений 3.1 Разработка архитектуры программных средств Разрабатываемое программное средство включает в себя две основные части: API, которое служит некой входной точкой для прикладных систем и сервер приема сообщений, который принимает сообщения, сформированные с помощью API от прикладных систем. Также в компоненты прикладной системы входит протокол соединения, идентификации и обмена данными между API и сервером. Разрабатываемое API является интерфейсом между ПО прикладной системы и сервером сообщений. Задачей API является установка соединения с сервером, обработка команд и формирование пакетов, отвечающих протоколу обмена сообщениями. Так как архитектура прикладной системы неизвестна, то программный интерфейс должен быть как можно более легковесным, что позволит органично встроить его в уже существующие программные продукты. Для удобства работы с интерфейсом разрабатываемое API собирается в подключаемую библиотеку для быстрого и легкого встраивания. Стоит отметить, что сервер не привязан к конкретной реализации интерфейса, т.е. в дальнейшем API можно переписать на другом языке программирования (для подсистем с программными средствами, реализованными на других языках). Единственное требование для работоспособности API – полная реализация протокола обмена данными с сервером приема и обработки сообщений. Сервер в свою очередь представляет собой мост от прикладных систем к серверу журнализации. Задача сервера – обработка входящих подключений, фильтрация сообщений в целях снижения нагрузки. Также сервер упрощает задачу журнализации благодаря относительно простому 38 протоколу – с которым можно работать даже на микроконтроллерах, которые могут не иметь достаточно ресурсов для работы с СУБД Cache напрямую. На рисунке 10 изображена диаграмма развертывания программного средства в нотации UML, отображающая архитектуру программных средств первичной обработки и передачи сообщений. Рисунок 10 – Диаграмма развертывания «Программные средства первичной обработки и передачи сообщений» 39 Физическое расположение программных средств не влияет на их работу, т.к. для соединения используется TCP –сокет. 3.1.1 Модель акторов Модель акторов представляет собой математическую модель параллельных вычислений, трактующую понятие «актор» как универсальный примитив параллельного расчета. Актор является вычислительной сущностью, которая в ответ на полученное сообщение может одновременно (или последовательно): ー отправить конечное число сообщений другим акторам; ー создать конечное число новых акторов; ー выбрать тип поведения, которое будет использоваться для следующего сообщения в свой адрес. Акторы образуют собой иерархическую систему, в которой каждый актор является чьим-то потомком за исключением корневого актора системы. Каждый актор отвечает за свою очень маленькую задачу; его состояние недоступно для изменения извне и его сбой обрабатывается актором- родителем. Акторы взаимодействуют друг с другом исключительно через пересылку сообщений-объектов; пересылка и обработка данных происходят асинхронно. Каждый актор имеет свой уникальный адрес (URL, англ. Uniform Resource Locator), по которому к нему могут обратиться другие акторы. Такой механизм обеспечивает минимальную связность, и каждый актор можно с легкостью заменить другим или протестировать отдельно от остальной программы. Основная идея проектирования приложения на базе системы акторов заключается в его построении на базе множества легковесных акторов, каждый из которых абсолютно независим от других. Так как отдельный актор отвечает за свою задачу, то при прочтении кода легко понять, что он делает и как себя ведет при тех или иных событиях. Сложная логика 40 программы строится на взаимодействии нескольких акторов, каждый из которых производит операцию над данными и отправляет их другим акторам. Стоит отметить, что как правило, система акторов не создает отдельный поток для каждого актора, а содержит пул потоков, из которого поток забирается при наличии входящего сообщения для актора, и возвращается после обработки этого сообщения. Благодаря этому одна система акторов может обслуживать миллионы акторов без существенной добавленной нагрузки. 3.1.2 Разработка архитектуры сервера на основе модели акторов Часто бывает так, что при проектировании платформы, предназначенного для обслуживания множества клиентов, проектировщики не сразу задумываются о асинхронности потоков данных и проектируют последовательную работу ПО, программисты вслед за ними пишут последовательный код и распараллеливают обработку данных только после выявления узких мест в коде, как правило, после провалов во время работы платформы в «боевом» режиме. Так как параллелизация происходит отдельно в различных участках программы, то получается код, крайне неудобный для чтения, работа которого не очевидна и может быть подвержена так называемым «состояниям гонки». С такими состояниями помогают бороться различные структуры синхронизации потоков (например семафоры) – но код становится еще менее интуитивным. К тому же, позицию каждого семафора нужно точно рассчитать, иначе не все вычисления будут произведены параллельно, что в свою очередь приведет к очередному снижению скорости работы приложения. Также случается так, что одно из «узких мест» оказывается глубоко в корневой архитектуре платформы – в таком случае ПО приходится выкидывать и переписывать с нуля. Именно поэтому при проектировании 41 платформы, отвечающего жестким требованиям к стабильности и пропускной способности, с самого начала необходимо учитывать то, что все основные вычисления должны выполняться асинхронно. При проектировании данной платформы было принято решение использовать модель акторов как основу архитектуры ПС. 3.2 Разработка программных средств сервера обработки сообщений 3.2.1 Разработка системы классов сервера Корневой актор системы запускает актор сокета. Для каждого входящего соединения имеются акторы обработки состояния соединения, обработки входящих сообщений и отправки сообщений на сервер журнализации. Обработка повторяющихся сообщений (с помощью ранее упомянутого алгоритма текущего ведра) была выделена в отдельный актор. Однако акторы каждого подключения не могут соединяться с БД напрямую, иначе для каждой подключенной системы придется создавать свое подключение с базой – поэтому в систему входит еще и актор, поддерживающий соединение с БД. На рисунке 11 изображена финальная диаграмма классов. Стоит отметить вспомогательные классы AppSocket и ServerSocket, созданные для взаимодействия акторов с сокетами соединения. Они необходимы из-за того, что асинхронные события, происходящие и обрабатываемые внутри отдельного актора теряют текущий контекст (отправителя сообщения, адрес конкретного актора и т.д.), наличие которого необходимо для дальнейшей обработки сообщения. Также данная диаграмма включает в себя классы ActualEvent, KeyValueEvent и KeyValuePair, импортированные из БД и служащие прокси-классами базы данных сервера журнализации. Для загрузки, хранения и сохранения конфигурации сервера сообщения имеется 42 класс SettingsStorage. Класс Server реализует в своем конструкторе основную бизнес-логику сервера сообщений и наследуется от класса TypedActor библиотеки Akka.Net. Также от класса TypedActor наследуются классы AppSocketActor и ServerSocketActor. Рисунок 11 – Диаграмма классов сервера обработки сообщений Сигнатуры классов, отвечающих за реализацию бизнес-логики сервера обработки сообщений, приведены в таблицах 4-13. 43 Таблица 4 – Свойства класса AppSocket Название свойства Тип свойства Описание свойства _parent IActorRef Хранит ссылку на родительский актор TCP сокета _client TcpClient Хранит настройки клиента TCP сокета SysKeyCode int Хранит код ответа от сервера при установлении соединения по TCP сокету Таблица 5 – Методы класса AppSocket Название метода Параметры Описание метода AppSocket sender: IActorRef; Конструктор класса AppSocket client: TcpClient StartConnection отсутствуют Инициирует соединение по TCP сокету Таблица 6 – Свойства класса AppSocketActor Название свойства Тип свойства Описание свойства _asock AppSocket Хранит настройки TCP сокета для конкретного актора Таблица 7 – Методы класса AppSocketActor Название метода Параметры Описание метода Handle message:TcpClient Обработчик события установления соединения по TCP сокету Handle message:string Обработчик события передачи сообщения по TCP сокету 44 Таблица 8 – Свойства класса SettingsStorage Название свойства Тип свойства Описание свойства ConnectionString string Хранит строку подключения к БД журнала событий AppSocketPort uint Хранит номер порта TCP сокета Instanse SettingsStorage Содержит конфигурацию сервера обработки сообщений, извлеченную из XML-файла PassiveComponents string Хранит информацию о компонентах ПС, работающих в режиме push Таблица 9 – Методы класса SettingsStorage Название метода Параметры Описание метода SettingsStorage отсутствуют Конструктор класса SettingsStorage Load отсутствуют Производит загрузку конфигурации сервера обработки сообщений из XML-файла Save отсутствуют Сохраняет конфигурацию сервера обработки сообщений в XML-файл Таблица 10 – Свойства класса ServerSocket Название свойства Тип свойства Описание свойства _actor IActorRef Хранит актор сервера _listener TcpListener Хранит слушателя TCP сокета _cancelsrc CancellationTokenSOurce Хранит объект, отвечающий за разрыв соединения 45 Таблица 11 – Методы класса ServerSocket Название метода Параметры Описание метода ServerSocket actor:IActorRef Хранит строку подключения к БД журнала событий ep: IPEndPoint Start uint Хранит номер порта TCP сокета Stop SettingsStorage Содержит конфигурацию сервера обработки сообщений, извлеченную из XML-файла AcceptConnections string Хранит информацию о компонентах ПС, работающих в режиме push Таблица 12 – Свойства класса ServerSocketActor Название свойства Тип свойства Описание свойства _ep IPEndPoint Хранит IP-адрес и номер TCP- порта сервера обработки сообщений _ssock ServerSocket Хранит сокет сервера обработки сообщений Таблица 13 – Методы класса ServerSocketActor Название метода Параметры Описание метода ServerSocketActor ep: IPEndPoint Конструктор класса ServerSocketActor Handle message:TcpClient Обработчик события установления соединения по TCP сокету Handle message:bool Обработчик события получения сообщения об успешном подключении 46 Диаграмма классов наглядно показывает отношения наследования, однако вследствие минимальной связанности акторов не видны взаимодействия между классами. Для отслеживания взаимодействий между акторами и вспомогательными классами требуется построить диаграмму последовательности (Sequence Diagram в нотации UML). На диаграмме 12 изображена последовательность действий при запуске системы акторов. Видно, как корневой актор Server обращается к хранилищу настроек, и в случае успешной их загрузки инициализирует актор сокета ServerSocketActor, принимающего входящие соединения и соединение с БД. Актор сокета в свою очередь инициализирует класс сокета ServerSocket, который служит прокси-объектом между низкоуровневыми соединениями и системой акторов. В случае успешного соединения выводится сообщение, уведомляющее о готовности сервера к приему входящих соединений. Рисунок 12 – Диаграмма последовательности «Запуск сервера» 47 После процесса инициализации сервер входит в свое основное состояние ожидания соединений. Следующей активностью является подключение компонента системы к серверу. Данная активность имеет две разновидности в зависимости от режима обмена сообщениями между компонентом системы и сервером сообщений. Данная активность описана UML-диаграммами на рисунках 13-14. На рисунке 13 описана активность для режима pull. На рисунке 14 – для режима push. Рисунок 13 – Диаграмма последовательности «Соединение в режиме pull» Рисунок 14 – Диаграмма последовательности «Соединение в режиме push» Данная диаграмма отображает последовательность действий при приеме подключения к серверу. Цепочка акторов создает новый актор 48 AppSocketActor, который в свою очередь создает прокси-класс AppSocket и передает ему принятое соединение. AppSocket производит идентификацию подключенного компонента и проверяет версию протокола, при прошествии всех проверок начинается обработка запросов от компонента ПС. Для каждого подключения создается своя пара AppSocket и AppSocketActor. В случае провала проверок соединение закрывается, а актор AppSocketActor и принадлежащий ему прокси-класс уничтожаются. В текущем состоянии компонент может отправлять сообщения или отправить запрос на защиту соединения. В запросе на защиту соединения участвует лишь компонент системы и класс AppSocket; при этом процессе не производится никаких сложных действий. Процесс приема сообщения более сложен; его диаграмма последовательности представлена на рисунке 15. Рисунок 15 – Диаграмма последовательности «Прием сообщения» При приеме сообщения оно проходит через два фильтра: прием сообщений только при защищенных соединениях (зависит от настройки) и упомянутый ранее фильтр алгоритма «текущего ведра». Далее сообщение отправляется актору-родителю класса AppSocket, где сообщение проходит 49 десериализацию (т.е. разбор принятой строки и формирование объекта). Для объекта создается новый прокси-класс Event, который заполняется данными принятого сообщения и отправляется в базу данных сервера журнализации с помощью метода Commit прокси-класса. Дальнейшая обработка сообщения проходит на сервере журнализации, а прокси-объект уничтожается из памяти при срабатывании сборщика мусора. В случае разрыва соединения или отсутствия доступа к объекту класса ActualEvent обрабатывается исключение, и запись последующих сообщений производится в лог файл. |