Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

К вопросу построения прототипа защищенных информационных систем. Третья редакция

Основные цели построения прототипа - научиться:
  • строить много проектные решения (много файловые сборки) в среде Visual Studio/C# (приложения, состоящие из одного .exe и нескольких .dll);
  • строить программные системы на основе нескольких программных приложений, взаимодействующих как в среде отдельного компьютера, так и в рамках локальной сети и Internet;
  • удаленно работать с конфиденциальной информацией SQL сервера, используя в качестве транспорта данных Интернет или незащищенный се
  • Основные цели построения прототипа - научиться:
    • строить много проектные решения (много файловые сборки) в среде Visual Studio/C# (приложения, состоящие из одного .exe и нескольких .dll);
    • строить программные системы на основе нескольких программных приложений, взаимодействующих как в среде отдельного компьютера, так и в рамках локальной сети и Internet;
    • удаленно работать с конфиденциальной информацией SQL сервера, используя в качестве транспорта данных Интернет или незащищенный сегмент локальной сети,
    • защищать клиентское приложение от несанкционированной модификации,

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

    В процессе построения прототипа решены следующие задачи:

    • аутентификации пользователя, инициирующего обмен;
    • авторизации пользователя в процессе работы;
    • ограничения доступа к функциям и записям таблиц базы данных информационной системы (управление доступом);
    • защиты трафика;
    • страничного представления информации клиенту;
    • компрессии информации;
    • защиты клиентского приложения от несанкционированной модификации;
    • адаптации структуры системы к информационной нагрузке,

    а также:

    • осуществлена реализация необходимых программных методов;
    • построено много проектное решение для пользовательского интерфейса,
    • построена программная система, состоящая из пяти взаимодействующих приложений на основе .Net Remoting (клиентское приложение, сервис взаимодействия с клиентом, сервис хранения запросов/ответов, КриптоСервер, база данных на SQL сервере),
    • разработан и реализован общий подход к настройке WEB-, .NET- сервисов и Windows приложений.

     

    Прибавления и изменения по отношению к первой редакции:

    1. Не рассматриваются и не упоминаются системы на основе ASP.Net и Web сервисов. Развитие прототипа осуществляется только на базе Remote .Net сервисов поверх IIS или Remote .Net сервера
    2. Кратко оттенены преимущества построения информационных систем на основе взаимодействующих Remote .Net сервисов
    3. Подробно рассмотрен измененный процесс аутентификации клиента
    4. Описан процесс взаимодействия клиентского singlecall сервиса с системой динамических абонентских ящиков на основе событийной модели
    5. Рассказано о новом алгоритме построения страницы результирующего набора данных
    6. Приведена схема защиты клиентского приложения от несанкционированной модификации.

    Особенности прототипа:

    • клиентское приложение прототипа свободно распространяется в Интернете, функционирует в незащищённой среде и защищено от несанкционированной модификации;
    • прототип не использует для клиентов учётные записи локальной сети Windows.

    Построение информационной системы на основе взаимодействующих .Net Remoting сервисов имеет определенное преимущество, - связь в сети одного сервиса к другим осуществляется по адресам URL формата (например: tcp://alpha:5000/ или http://localhost:80/). Это даёт возможность отладить все компоненты системы, используя только один компьютер. И создать на их основе реальную систему такую, как на показано рисунке. Для адаптации информационной системы к реальным нагрузкам можно, достаточно произвольно, менять структуру компьютерной составляющей. Например, если система для адекватной реакции на нагрузку, должна иметь несколько IIS серверов на разных компьютерах, то проектировщик добавит в схему дополнительно нужное число компьютеров для размещения серверов хранения запросов/ответов и т.п. Собираем нужную программно-техническую структуру системы из "кубиков".

    Прототип содержит три базовых компонента (схемотехнических элемента, "кубика") - КриптоСервер (сервер бизнес-логики), Remote .Net сервер хранения запросов/ответов на базе консольного приложения и сервер управления взаимодействием с удаленными клиентами. В качестве связующих стрелок используются адреса URL. К одному базовому схемотехническому элементу - серверу хранения запросов/ответов - можно с одной стороны подключить несколько IIS элементов c Remote .Net сервисами, а с другой несколько других элементов - серверов бизнес-логики, и получить вычислительный узел. Меняя число и состав вычислительных узлов, решаем задачу адаптации структуры системы к информационной нагрузке.

    Программный комплекс из двух элементов - сервера управления взаимодействием с удаленными клиентами и Remote .Net сервера хранения запросов/ответов - серьёзный инструмент для создания распределенных систем. В абонентский ящик можно положить, как запрос клиента на выполнение работы сервером, так и сообщение клиента о готовности выполнить работу, которую закажет сервер.

    Построение информационной системы на основе взаимодействующих .Net Remoting сервисов целесообразно также и экономически - клиентские лицензии для работы с базой данных (например, Oracle) требуется установить только на компьютеры c КриптоСервер-ами. Так для 1000 клиентов достаточно двух лицензий. И ещё один интересный момент - достаточно всего одной! дополнительной учетной записи клиента, от имени которого работаем с базой данных и запускаем КриптоСервер-а. Клиент не работает напрямую с базой данных.

    Построенный прототип реально представляет собой распределённую систему управления централизованным каталогом видео фильмов. Самостоятельно может работать в студенческих общежитиях или локальной сети квартала. Как прототип может служить базой для построения распределённых информационных систем в банковском деле (удаленный АРМ операционного дня, АРМ клиента банка), построения общегородских распределённых информационных систем по наличию лекарств в аптеках, построения информационных систем супермаркетов, товарных складов и т.п.

    Аутентификация пользователя и построение сессии.

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

    Структура учетной записи

     

    N/N Name Data Type Size
    1 GUID uniqueidentifier 16
    2 Имя nvarchar 64
    3 hshLogin binary 20
    4 hshPassword binary 20
    5 Cmd int 4
    6 e_mail nvarchar 64
    7 hshPinCod binary 20
    8 kiPinCod binary 32

    3, 4 и 7 поле строки содержат hash представления Login, Password и PinCod-а пользователя.

    5 поле (cmd) содержит битовый вектор доступа к функциям и объектам системы. Поле 8 содержит параметры шифрования файла на клиентской машине, содержащего hshLogin и hshPassword.

    Учетные записи предопределённых пользователей защищенной информационной системы - Администратора и Гостя, генерируются при первоначальном запуске Windows .Net приложения "КриптоСистема" на любом из КриптоСерверов. Учетные записи других пользователей создаются Администратором.

    Администратор системы, используя Windows. Net приложение "RSAKeyPairGen.exe", генерирует также и ключевую пару ассимметричного криптографического алгоритма. Открытый ключ, вместе с клиентским Windows.Net приложением "wсКаталогВидео", передается пользователю.

    Предопределённый пользователь может получить доступ к данным или как Гость, с минимальными возможностями (только просмотр имеющихся в наличии фильмов), или как Администратор, с почти неограниченными возможностями, но для этого ему надо знать Login и Password. Гость и Администратор не имеют PinCod-а. Кроме группы предопределённых пользователей существует группа пользователей, являющихся владельцами фильмов. Для своего фильма владелец может редактировать все параметры. Для совместного фильма - только ограниченное число своих параметров.

    Запуская клиентское приложение на своей рабочей станции, пользователь любой группы попадает в состояние регистрации. Его просят ввести аутентификационную информацию - Login и Password или PinCod. Информация вводится стандартным защищенным способом с использованием DPAPI-функция CredUIPromptForCredentials. Реализованы два варианта аутентификации пользователя:

    В дальнейшем, в байтовых последовательностях будем выделять фрагменты, - без шифрования (…), шифрованные открытым ключем {…}, шифрованные симметричным ключем […].

    Вариант 1. Пользователь вводит информации в поля Login и Password. Клиентское приложение создаёт временные код сессии (КС), ключ (Key) и initialization vector (IV) симметричного алгоритма шифрования. Последовательность запроса = (КС +IV+0x00)+{Key}+[0x0003] передаётся КриптоСерверу для получения "временного параметра" ВП. По его получению программа генерирует постоянные КС и Key сессии, и временный IV. Для Login и Password строятся их hash представления, к ним добавляется "временной пар аметр", которые вместе шифруются симметричным ключом; симметричный ключ шифруется открытым ключом ассимметричного алгоритма. Байтовая последовательность = (КС+IV+0x00)+ {Key}+ [0x0001+ ВП+ hash Login+hash Password] передается КриптоСерверу.

    Вариант 2. Пользователь вводит информацию только в поле Password (PinCod). Клиентское приложение создаёт временные КС, Key, IV, строит байтовую последовательность запроса "временного параметра" = (КС +IV+0x00)+{Key}+[0x0003] и передаёт её КриптоСерверу. После получения ВП от КриптоСервера программа строит временные КС, Key, IV и hash представление PinCod-а, добавляет к ним "временной параметр", шифрует и делает запрос КриптоСерверу на предмет наличия зарегистрированного пользователя с таким PinCod-ом. Если сервер подтверждает наличие, передавая Key и IV шифрования, то программа считывает и дешифрирует hash представления Login и Password из файла hshLP.bin и далее аналогично первому варианту. Расположение файла hshLP.bin задается в файле настройки - или на съемном носителе (дискета, cd, флеш) или крипто защищённом личном разделе жесткого диска.

    Схема передачи запроса КриптоСерверу: клиентское приложение -> сервер взаимодействия с клиентом -> сервер хранения запросов/ответов ->КриптоСервер

    - сервер взаимодействия с клиентом это Remote .Net сервер "crService_KatalogVideo" на базе консольного приложения - для клиентов локальной сети, IIS - для клиентов Интернета. Сервер взаимодействия с клиентом обеспечивает функционирование Remote .Net singlecall сервисов "сrService_KatalogVideo_Lib" управления взаимодействием с клиентом. Информационные запросы клиентов динамически порождают создание копий singlecall сервиса в среде Remote .Net сервера или IIS. Для каждого клиента - своя копия. Как только ответ будет передан клиенту, его копия singlecall сервиса уничтожается.

    - сервер хранения запросов/ответов это Remote .Net сервер "rServer_УправлениеЗапросОтвет" на базе консольного приложения. Сервер обеспечивает функционирование Remote .Net singleton сервиса управления системой динамических абонентских ящиков.

    Сервисы взаимодействия с клиентом и управления системой динамических абонентских ящиков никаких крипто преобразований над байтовыми последовательностями запроса/ответа не осуществляют. Они создают канал в Интернете (сегменте локальной подсети), по которому передаётся шифрованная информация.

     

    Взаимодействие Remote .Net сервисов с другими приложениями реализовано на основе интерфейсов ими представляемых, например, для сервиса управления системой динамических абонентских ящиков

    
    public delegate void dlgEventHandlerОтвет(short j);
    
    public interface IКлиент {
      short БронированиеАбонентскогоЯщика(byte[] gd);
      void  ПоложитьЗапросВЯщик(short idx,byte[] bv,dlgEventHandlerОтвет vtHandler);  
      void  ВзятьОтветИзЯщика(short idx,byte[] gd);  
    }
    

    Реализация ожидания и обработки события ответа на запрос в сервисе взаимодействия с клиентом

    
    public class crServer_KatalogVideo_Impl: MarshalByRefObject,IОбработкаЗапроса,IКлиент
    {
      static AutoResetEvent[] evtОжидание = new AutoResetEvent[1000];
      ...
      //-- Функция обработки ответа на запрос клиента
      //-- вызывается, как только ответ помещен 
      //-- в абонентский ящик клиента 
      [OneWay]
      public void fОтвет(short j) {
        if(j>=0){
          //-- Продолжаем обработку запроса данным сервисом.
          if(!(evtОжидание[j]==null)) ((AutoResetEvent)evtОжидание[j]).Set();
        } 
      }
    ...
     
      //-- Пытаемся бронировать динамический абонентский ящик
      for(i=10;i>=0;i--) { //-- Ждем освобождения абонентского ящика
        idx=iКлиент.БронированиеАбонентскогоЯщика(gd);
        if(idx>=0) break;
        Thread.Sleep(2000);
      }
      if(idx<0)	return new byte[2]{1,2}; //-- Ошибка записи строки запроса
       
      //-- создаём объект для ожидания 
      evtОжидание[idx]=new AutoResetEvent(false); 
      
      //-- В метод удаленного сервиса передается делегат обработчика события
      iКлиент.ПоложитьЗапросВЯщик(idx,bv,new dlgEventHandlerОтвет(fОтвет));
      //-- Ожидаем байтовую строку ответа
      if(evtОжидание[idx].WaitOne(iTimeOut,false)) 	//-- не допустим вечный цикл 
      {//-- Не time-out. Запрос обработан
        evtОжидание[idx].Reset();
        evtОжидание[idx]=null;
        return(iКлиент.ВзятьОтветИзЯщика(idx,gd));	//-- Сериализованный ответ
      }
      else 
      {//-- Time-out
        return new byte[2]{1,2}; //-- Ошибка записи строки запроса
      }
    ...
    

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

    Сервис хранит информацию о запросах/ответах в следующих структурах:

     

    byte[] даяКодСостояния значения компоненты: 0xff-бронировано, 0x00-свободно, 0x01-запрос, 0x02-запрос обрабатывается; 0x03-запрос обработан.
    Guid[] даяСессия компонента хранит Guid сессии
    object[] даяЗапросОтвет компонента хранит сериализованное, сжатое и шифрованное представление запроса/ответа
    DateTime[] даяДлительность компонента хранит максимально допустимое время обработки запроса (длительность бронирования сессией динамического абонентского ящика)
    dlgEventHandlerОтвет[] даяОтвет компонента хранит информацию, необходимую для вызова функции обработки ответа сервиса "сrService_KatalogVideo_Lib" по завершению обработки запроса.

    Совокупность компонент разных векторов с одним индексом образуют динамический почтовый ящик (префикс "дая").

    - КриптоСервер это Windows .Net приложение, взаимодействующее с сервисом управления системой динамических абонентских ящиков посредством Remote .Net технологии. Все решения принимаются и выполняются только на уровне КриптоСерверов. КриптоСервера являются "мозгом" всей пяти уровневой системы. Каждый КриптоСервер постоянно сканирует (точнее, обращается в цикле к сервису хранения запросов/ответов) вектор даяКодСостояния[] сервиса хранения запросов/ответов и при наличии запроса переходит к его детальному анализу и выполнению. Если запрос может быть обработан данным КриптоСервером, то анализ продолжается, иначе работа над запросом завершается без уничтожения запроса. Запросы разделены на группы по признаку максимальной длительности выполнения и есть серверы, выполняющие только короткие запросы.

    Если пользователь с данными Login и Password создан (имеется соответствующая запись в таблице Владельцы информационного SQL сервера), то генерируется запись в таблицу сессий информационного SQL сервера и запись в структуры сервиса управления системой динамических абонентских ящиков и КриптоСервер продолжает сканирование. Группа функций с кодом 0x00 отвечает за регистрацию клиента. Любой пользователь может активизировать несколько самостоятельных сессий.

    Структура записи таблицы сессий

     

    N/N Name Data Type Size Примечание
    1 gdСессия uniqueidentifier 16 Код (guid) сессии
    2 gdКлиент uniqueidentifier 16 Код (guid) клиента (владельца), связь с таблицей Владельцы
    3 dtСессия datetime 8 Time-out
    4 tdsKey binary 24 Ключ симметричного шифрования
    5 Cmd int 4 Битовый вектор доступа
    6 ivKey binary 8 IV симметричного алгоритма шифрования
    7 strЗапрос ntext 16 Храним SELECT запроса фильмов
    8 hs image 16 Храним сериализованный список Guid

    По завершению обработки запроса КриптоСервер записывает ответ в компоненту вектора даяЗапросОтвет[] и устанавливает компоненту даяКодСостояния[] =0x03. Сервис хранения запросов/ответов, используя переданный делегат, активизирует функцию fОтвет обработки события в сервисе взаимодействия с клиентом. Функция толкает застывший клиентский сервис, который забирает ответ из динамического абонентского ящика и отправляет его байтовую строку через Интернет (сегмент локальной подсети) клиенту. Сервис прекращает своё существование.

    Структура байтовой последовательности ответа в случае регистрации клиента

    Ошибка - (двухбайтовый код ошибки)

    Штатно - (0x00+0x00+IV)+[симметрично зашифрованное Info]

    Структура Info ответа для регистрации:

    [cmd клиента]+[guid аутентифицированного клиента]+[размер страницы]+[имя клиента]

    Структура байтовой последовательности для общего случая информационного запроса/ответа:

    Запрос:

    (КС+IV+индекс группы команд)+[Info]

    Структура Info запроса:

    [индекс команды в группе+параметры команды]

    Структура ответа:

    Ошибка - (двухбайтовый код ошибки)

    Штатно - (0x00+0x00+IV)+[Info]

    В общем случае Info ответа содержит результирующий набор данных в виде строк отсортированного массива объектов. Размер массива может превышать допустимые границы, например, в случае запроса показать все фильмы. Для работы с подобными наборами данных используем страницы. Идея проста - результирующий набор данных делится на страницы и за единичный акт обмена на рабочую станцию пользователя передаётся одна страница отсортированного результирующего набора данных. С целью уменьшения трафика, предложение SELECT для построения страничного набора данных и его параметры передаются по сети единожды и хранятся в полях строки таблицы Сессий (strЗапрос, hs). Для получения следующей страницы достаточно передачи её номера. Размер страницы в записях - параметр настройки сервиса управления системой динамических абонентских ящиков. По отдельному запросу величину размера получают КриптоСервера. Основную часть задачи страничного представления информации клиенту решает SQL сервер двумя динамическими запросами:

    CREATE PROCEDURE au_getPageФильмыDel 
    @Sel_1 ntext,
    @RowNum int,
    @Sel_2 ntext
    AS
    -- очистим таблицы GUID Фильмов
    TRUNCATE TABLE  #gdФильмы
    TRUNCATE TABLE  #gdTmp
    -- Запись отсортированных ключей в #gdTmp
    EXECUTE(@Sel_1)
    -- Перепись суррогатных ключей страницы
    INSERT INTO #gdФильмы(GUID) 
      	SELECT GUID FROM #gdTmp WHERE RowNum > @RowNum  ORDER BY RowNum"
    TRUNCATE TABLE  #gdTmp
    -- Вот эти данные уходят на клиента
    EXECUTE(@Sel_2)
    GO
    

    Каждый "КриптоСервер" имеет один Connect с базой данных. В рамках Connect-а строятся две временные таблицы - #gdФильмы и #gdTmp

    CREATE TABLE #gdФильмы (RowNum int IDENTITY,[GUID] [uniqueidentifier]);
    CREATE TABLE #gdTmp (RowNum int IDENTITY,[GUID] [uniqueidentifier])
    

    Первым динамическим запросом "режем" таблицу по длине и заполняем временную таблицу #gdTmp значениями суррогатных ключей выбранных отсортированных строк исходной таблицы

    INSERT INTO #gdTmp(GUID) SELECT TOP ... GUID FROM Фильмы WHERE ... ORDER BY ... 
    

    Вторым динамическим запросом "режем" выбранные строки таблицы по ширине и возвращаем выборку

    SELECT f.GUID, f.Преф, f.Название_рус ...
      FROM Фильмы f INNER JOIN #gdФильмы g ON f.GUID=g.GUID ORDER BY g.RowNum
    

    Фрагмент программы получения страницы:

    ...
    //-- Получим страницу выборки по фильмам  
    sscФильмы.Parameters.Clear();
    sscФильмы.Parameters.Add("@Sel_1", SqlDbType.NText).Value = Sel_1;
    sscФильмы.Parameters.Add("@RowNum ", SqlDbType.Int).Value = RowNum;
    sscФильмы.Parameters.Add("@Sel_2", SqlDbType.NText).Value = Sel_2;
    sscФильмы.CommandText = "au_getPageФильмыDel"; 
    sscФильмы.CommandType = CommandType.StoredProcedure;
    dsКриптоСистема.Фильмы.Clear();
    sdaФильмы.Fill(dsКриптоСистема,"Фильмы");
    dsКриптоСистема.Фильмы.AcceptChanges();
    

    В процессе формирования ответа страница обрабатывается Zip компрессором данных. Привожу фрагмент программы сериализации и компрессии страницы:

    //-- Построим вектор строк из таблицы результата
    int max=dsКриптоСистема.Фильмы.Count;
    object[]objArray=new Object[max];
    //-- objArray   страница
    for(int i=0;i<max;i++) objArray[i]=dsКриптоСистема.Фильмы.Rows[i].ItemArray;
    //-- Сериализация и компрессия
    if(!binSerObject(objArray)) {. . .} //-- сериализация
    if(!Компрессор())  {. . . }         //-- компрессия
    

    Авторизация пользователя при дальнейших запросах производится по коду сессии и параметрам симметричного алгоритма шифрования (ключу и IV шифра).

    Ограничения доступа пользователя к функциям и записям таблиц базы данных информационной защищенной системы задаются битовым вектором "cmd". Решение по ограничению доступа принимаются КриптоСервером (уровень бизнес-логики).

    Защита трафика осуществляется путем шифрования симметричным ключом сессии передаваемой байтовой последовательности.

    Для защиты передачи симметричного ключа сессии используется открытый ключ

    Защита клиентского приложения от несанкционированной модификации реализована так:

    • клиентское приложение создано в форме много проектного решения и компилируется с использованием строгих имен,
    • его узловая сборка (файл clsStartCrypto.dll) зашифрована в файл clsStartCrypto.cry,
    • если клиент идентифицирован, то КриптоСервер передаёт клиентскому приложению параметры дешифрования файла clsStartCrypto.cry,
    • клиентское приложение дешифрирует файл, загружает сборку, создает и активизирует объект заданного класса (допустим и вариант пересылки сборки КриптоСервером на клиентский компьютер):
      . . .
      //-- Дешифруем clStartSer.cry (крипто clStartSer.dll)
      //-- ivKey - параметры дешифрования, переданные КриптоСервер-ом
      //-- xbb <-- clStartSer.dll (byte[]xbb - переменная уровня класса)
      if(!TDESDecryptStartCrypto(ivKey)) return false;
      Assembly asStartSer=null;
      object obj=null;
      try {
        //-- Загружаем сборку
        asStartSer=Assembly.Load(xbb);
        Type[] mytypes = asStartSer.GetTypes();
        obj = Activator.CreateInstance(mytypes[0],null,null);
        return true;
      }
      catch
      {return false;}
      

    Сборка clsStartCrypto.dll состоит из одного класса. Для доступа к его методам используются делегаты. Сборка должна компилироваться в процессе компиляции всего приложения, но не один элемент приложения не должен напрямую ссылаться на сборку clsStartCrypto.dll (не должен, используя new, создавать объект из класса, содержащегося в сборке).

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

    Реализация программных методов хеширования, сериализации типов, компрессии информации и шифрования

    //-- Переменные уровня класса	
    byte[] xbb;
    MemoryStream xms;
    byte[] TDESKey=byte[24];
    byte[] TDESIV=byte[8];
    int xbbN;
    //-- =================
    //-- == Хеширование ==
    //-- =================
    //-- Формируем hash код строки
    //====================================
    private byte[] hКод(string s){
      UnicodeEncoding UE = new UnicodeEncoding();
      //-- Преобразование строки в вектор байтов.
      byte[] bv = UE.GetBytes(s);
      //-- Создадим объект SHA1Managed для формирования hash значения.
      SHA1Managed SHhash = new SHA1Managed();
      //-- Построим hash значение для байтового вектора.
      return SHhash.ComputeHash(bv);
    }
    //-- ========================
    //-- == Сериализация типов ==
    //-- ========================
    //-- Бинарная сериализация известного объекта 
    //-- В нашем случае зто вектор строк результирующего набора данных
    //-- xms <-- байтовое представление объекта
    //=========================================================
    private bool binSerObject(object obj){
      try	{
        xms=new MemoryStream();
        BinaryFormatter binForm=new BinaryFormatter();
        binForm.Serialize(xms,obj,null);
        xms.Position=0;
        return true;
      }
      catch {return false;}
    }
    //-- Бинарная десериализация известного объекта из памяти
    //-- xms <-- байтовое представление объекта
    //=========================================================
    private object binDeSerObject(){
      try	{
        BinaryFormatter binForm=new BinaryFormatter();
        return binForm.Deserialize(xms,null);
      }
      catch {return null;}
    }
    //-- Формируем 4-х байтовое представление int
    //-- ii   целое
    //-- k    индекс в xbb 
    //-- xbb   целое
    //=================================================
    private void IntToXBB(int ii,int k) {
      byte[] bt=BitConverter.GetBytes(ii);
      bt.CopyTo(xbb,k);
    }
     
    //-- Формируем 4-х байтовое представление int
    //-- xms   целое
    //=================================================
    private void IntToXms(int ii) {
      byte[] bt=BitConverter.GetBytes(ii);
      xms.Write(bt,0,bt.Length);
    }
    //------------ Восстановление int ------------
    //-- int   байтовое представление xbb
    //==========================================================
    private int XBBToInt()
    {return BitConverter.ToInt32(xbb,0);}
    //------------ Восстановление int ------------
    //-- int   байтовое представление xms
    //==========================================================
    private int xmsToInt() {
      byte[]bt=new Byte[4];
      xms.Read(bt,0,4);
      return BitConverter.ToInt32(bt,0);
    }
    //-- Формируем 8-и байтовое представление long
    //-- xms   long
    //=================================================
    private void LongToXms(long ii) {
      byte[] bt=BitConverter.GetBytes(ii);
      xms.Write(bt,0,bt.Length);
    }
    //------------ Восстановление long ------------
    //-- long   xms(байтовое представление long)
    //==========================================================
    private long xmsToLong() {
      byte[]bt=new Byte[8];
      xms.Read(bt,0,8);
      return BitConverter.ToInt64(bt,0);
    }
    //-- Формируем 8-и байтовое представление DateTime в xms
    //-- xms   DateTime
    //========================================================
    private static void DateTimeToXMS(DateTime dt) {
      LongToXMS(dt.Ticks);
    }
    //-- Восстановление DateTime из xms
    //-- DateTime   xms
    //==========================================================
    private static DateTime xmsToDateTime() {
      long n=xmsToLong();
      return new DateTime(n); //-- DateTime <--  long
    }
    
    //-- Работа с байтовым представлением строкового типа
    //-- s - Строковый тип; bt - байтовое представление
    //==========================================================
    byte[]bt=UnicodeEncoding.UTF8.GetBytes(s);   //-- byte[]   s
    string s=UnicodeEncoding.UTF8.GetString(bt); //-- s   byte[]
    
     
    //-- ===========================
    //-- == Компрессия информации ==
    //-- ===========================
    //-- Компресор 
    //-- вход:  xbb (вектор для компресии)
    //-- выход: xbb (длина исходного(4)+сжатый вектор)
    //=========================================================
    private bool Компрессор(){
      if(xbb.Length==0) return true;
      byte[]bb;
      try	{
        bb=ZipBase.Compress(xbb);
        int m=xbb.Length;
        xbb=new byte[4+bb.Length];
        IntToXBB(m,0);
        bb.CopyTo(xbb,4);
        return true;
      }
      catch {return false;}
    }
    //-- Декомпрессор 
    //-- вход:
    //-- фрагмент xms содержит компресированный байтовый вектор,
    //-- указатель стоит на начале фрагмента
    //-- выход;
    //-- xms	<-- декомпресированное Info
    //===============================================================================
    private bool Декомпрессор(){
      byte[] bb=new byte[((int)xms.Length)-4];
      try  {
        int n=xmsToInt();	      //-- длина исходного Info
        byte[] bb1=new byte[n];	//-- место для декомпрессированного Info
        xms.Read(bb,0,bb.Length);	//-- bb <-- компрессированное Info
        ZipBase.Uncompress(bb1,bb);
        xms.Close();
        xms=new MemoryStream(bb1,0,bb1.Length);
        return true;
      }
      catch  {
        xms.Close();
        return false;
      }
    }
    
    //-- ================
    //-- == Шифрование ==
    //-- ================
    
    //-- TDES крипто 
    //-- вход:  xbb (вектор для шифрования)
    //-- выход: xbb (шифрованный вектор)
    //=========================================================
    private bool TDESEncrypt(){
      if(xbb.Length==0) return true;
      CryptoStream cs=null;
      MemoryStream ms=null;
      try	{
        byte[]bb=new Byte[32];
        byte[]key=new byte[24];
        byte[]iv=new byte[8];
        new RNGCryptoServiceProvider().GetBytes(bb);	
        //-- байтовый вектор bb содержит хорошо рандомизированную величину
        for(int i=0;i<8;i++) TDESIV[i]=bb[i];
        TDESKey.CopyTo(key,0);
        TDESIV.CopyTo(iv,0);
        ms=new MemoryStream();
        cs=new CryptoStream(ms,tdes.CreateEncryptor(key,iv),CryptoStreamMode.Write);
        cs.Write(xbb,0,xbb.Length);
        cs.FlushFinalBlock();
        xbb=ms.ToArray();
        cs.Close();
        ms.Close();
        return true;
      }
      catch {
        if(cs!=null) cs.Clear();
        if(ms!=null) ms.Close();
        return false;
      }
    }
    //-- TDES декрипто 
    //-- фрагмент MemoryStream xms содержит шифрованную байтовую последовательность,
    //-- указатель стоит на начале фрагмента
    //-- ln <-- длина фрагмента 
    //===============================================================================
    private bool TDESDecrypt(int ln){
      CryptoStream cs=null;
      try	{
        byte[]key=new Byte[24];
        byte[]iv=new Byte[8];
        TDESKey.CopyTo(key,0);
        TDESIV.CopyTo(iv,0);
        cs=new CryptoStream(xms,tdes.CreateDecryptor(key,iv),CryptoStreamMode.Read);
        xbbN=(int)cs.Read(xbb,0,ln);
        cs.Close();
        return true;
      }
      catch {
        if(cs!=null) cs.Clear();
        return false;
      }
    }
    

    В качестве Web сервера используется IIS, с максимально отключенными возможностями.

    В качестве Remote .Net сервера используется консольное приложение.

    В качестве ассимметричного алгоритма шифрования используется 1024 битный RSA, в качестве симметричного - TrippleDES.

    Сервисы взаимодействия с клиентом и хранения запросов/ответов ни под каким предлогом не могут войти во внутреннюю локальную сеть и получить доступ к КриптоСерверам и данным информационного SQL сервера!!!!

    Все приложения системы (клиентские, Remote сервис под Web сервер, Remote сервис под Remote сервер, КриптоСервер и RSAKeyPairGen) написаны на C#. Клиентское Windows.Net приложение для работы с Remote .Net сервисом на IIS сервере или с Remote .Net сервисом на Remote .Net сервере написано в формате много проектного решения (много файловой сборки).

     

    Что должно быть в промышленной версии, но отсутствует в прототипе:

    - проработка вопросов сопровождения ПО, включая upgrate клиентской части программной системы

    - сбор и накопление статистики для будущих эвристических алгоритмов фильтрации запросов

    - счетчики загрузки и производительности информационной системы

    В настоящее время для фильтрации запросов применяется шифрование, "временной параметр" и отклонение сессией текущего запроса, если не выполнен предыдущий. Возможно ошибочное завершение выполнение запроса по time-out.

    Графический интерфейс пользователя для работы с данными, как в Интернете, так и локальной сети абсолютно идентичен и реализован в одном приложении. Выбор канала обмена (Tcp или Http) задается в файле "НастройкаWebRemoteServiceКлиента.txt" настройки приложения. Разница в работе ощущается лишь по длительности операции загрузки страницы данных с информационного SQL сервера в локальную базу данных.

    Внешний вид панелей графического интерфейса пользователя

     

    Клиентское приложение построено в форме много проектного Visual Studio (VS-) решения (много файловой сборки), основу которого составляют четыре проекта - clsApp, dbДоступ, clsStartCrypto и wcКаталогВидео. Решение компилируется с использованием строгих имён.

    Первый проект - clsApp, реализует построение класса общих (глобальных) параметров решения, включая описание и определение делегатов общих функций всего проекта. Он не ссылается ни на один другой проект решения, но на него могут ссылаться все. Иными словами, его видят все, он не видит никого. В последовательности компиляции проект clsApp стоит первым номером. Особенностью данного класса является определение здесь общих параметров как статических переменных:

      static public dgtРегистрацияПользователя	РегистрацияПользователя=null;
      static public dgtАнализPinCod			АнализPinCod=null;
    
    

    Второй проект - dbДоступ, содержит реализацию локальной базы данных. В последовательности компиляции он стоит вторым номером.

    Третий проект - clsStartCrypto, является реализацией интерфейса клиентского приложения с КриптоСервером. Это узловой проект всего решения, и его сборка передаётся клиенту в зашифрованном виде.

    Четвёртый проект - wcКаталогВидео, содержит ссылки на все другие проекты решения. Он видит всех, его не видит никто. В последовательности компиляции он последний. Содержит описание единого окна решения и реализацию общих функций пользовательского интерфейса.

    Остальные проекты или содержат описания оконных панелей графического интерфейса и реализуют соответствующую функциональность, или реализуют функциональность вывода отчетов (реализован вывод отчетов в форматах HTML и CrystalReport).

    Всё хорошо, но удручает отсутствие возможности выгрузки из памяти не нужной сборки.

    Также, для построения VS-решений применяется внешняя Zlib.dll, реализующая функциональность компрессора данных.

    Общий подход к настройке .Net сервисов и приложений

    Файлы "app.config" и "Web.config" содержат дополнительный фрагмент

    <appSettings>
      …..
      <add key="pathSetting" value="XXX"/>
    </appSettings>
    

    XXX - или пусто "", или полный путь к папке с дополнительным файлом настройки, например C:\НастройкаWebRemoteServiceКлиента\

    Доступ к фрагменту:

    string ss=System.Configuration.ConfigurationSettings.AppSettings["pathSetting"];
    

    Доступ к дополнительному файлу настройки:

    ss+="НастройкаWebRemoteServiceКлиента.txt";
    StreamReader sr= new StreamReader(ss,System.Text.Encoding.Default,true);
    

    Анализ файла настройки

    //-- Анализ протокола - Tcp или Http
    HostUrl = rp(sr);
    if(HostUrl.IndexOf("tcp",0,3)<0)
    {//-- Запуск RemoteService на IIS
      HostUrl+=@"RemoteServiceOnWebServer/RemoteServiceOnIIS_Uri.soap";
      fServer=false;
    }
    else
    {//-- Запуск RemoteService на RemoteServer
      HostUrl+=@"RemoteServer/rServer_KatalogVideo_Uri";
      fServer=true;
    }
    

    и т.д. ...

    Содержимое файла настройки "НастройкаWebRemoteServiceКлиента.txt":

    //--Настройка WebService клиента и Remote Service клиента
    //--==================================================
    //-- фрагмент Url для Remote сервера или Web сервера 
    http://localhost:80/  //-- Фрагменты   tcp://localhost:5000/ (Remote)  http://localhost:80/(Web)
    //--
    //--Path доступ к каталогу файла HTML
    C:\ НастройкаWebRemoteServiceКлиента
    //--Path доступ к каталогу файла Crystal Report
    C:\ НастройкаWebRemoteServiceКлиента
    //--Path доступ к каталогу файла hshLP.bin
    //-- этот каталог должен располагаться на личном носителе!!!
    //-- (например - флоппи или в Cripto-папке личного profile), 
    !!! 	//--если "!!!", то hshLP.bin располагается в ["APPDATA"]+"\MyCrypto\" пользователя
    

    Анализ дополнительного файла настройки

    //-- Чтение параметра из файла настройки
    private string rp(StreamReader sr)
    {
      string x,y,z;
      int n,i;
      //-- Пропуск строк комментария
      do {
        x=sr.ReadLine(); //-- Читаем строку файла настройки
        if(x.Length<4) x+="   ";
      }			
      while(x.Substring(0,4)==@"//--");
      //-- Анализ строки
      n=x.IndexOf(@"//--",0,x.Length);	//-- Отбросим комментарии в конце строки,
                                       //-- если они есть
      n=(n<0)?x.Length:n;
      y=x.Substring(0,n);
      x="";
      z="";
      //-- отбрасываем символы управления, такие как "TAB" 
      for(i=0;i<n;i++) {
        if(char.IsControl(y,i)){z=" ";}
        else {
          x=x+z+y.Substring(i,1);
    	z="";
        }
      }
      return x.Trim();
    }
    

     

     

    Аннотация

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


    Может пригодится:


    Автор: Владимир
    Прочитано: 4263
    Рейтинг:
    Оценить: 1 2 3 4 5

    Комментарии: (0)

    Добавить комментарий
    Ваше имя*:
    Ваш email:
    URL Вашего сайта:
    Ваш комментарий*:
    Код безопастности*:

    Рассылка новостей
    Рейтинги
    © 2007, Программирование Исходники.Ру