Приклад використання Private Object Security в Delphi
Приклад використання Private Object Security в Delphi
При створенні серверних додатків часто постає питання розмежування доступу різних груп користувачів до функцій цього додатка. Якщо сервер працює з системою, яка має власну реалізацію конторль доступу (сервер баз даних, файлова система і т.п.), то рішення очевидно - перекласти цю задачу на саму цільову систему. Однак в деяких случаех цей спосіб виявляється непридатний - або в цільовій системі немає власного механізму, або існує необхідність реалізувати алгоритм розмежування, відмінний від існуючого. У цьому випадку, за великим рахунком, у програміста є два шляхи:
- реалізувати весь механізм захисту самостійно
- використовувати наданий операційною системою Windows механізм "Private Object Security"
На мій погляд, другий варіант має наступні важливі переваги:
- Він реалізований командою професіоналів в даній, вельми делікатній, області
- Код його реалізації протестований величезною кількістю користувачів, а виявлені помилки оперативно усуваються командою розробників, тобто без нашнего участі.
- Системний механізм надзвичайно гнучкий, зручний і, що дуже важливо, добре знайомий системним адміністраторам.
Цей шлях і стане предметом обговорення в даній статті.
Етапи великого шляху
Не треба лякатися :) Насправді шлях цей не такий вже і великий, і код, написаний одного разу, може бути з успіхом використаний повторно.
Весь процес реалізації захисту на основі "Private Object Security" досить чітко розбивається на кілька цілком відокремлених етапів, і це, на мій погляд, є додатковим плюсом, так як така відособленість в значній мірі знижує ймовірність появи "перехресних" помилок. Етапи ці наступні:
- Визначити, які саме функції сервера вимагають управління доступом
- На основі попереднього етапу визначити набір прав, що дає доступ до тих або інших функцій або їх групам і оформити їх у вигляді набору констант.
- Визначити, які визначені Вами і, опціонально, стандартні права і їх комбінації буду відповідати базовим правам GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE і GENERIC_ALL.
- Створити і проініцілізіровать дескриптори захисту, після чого, при необхідності, зберегти їх в постійному сховищі.
- Реалізувати механізм, що дозволяє системному адміністратору змінювати налаштування Вашого захисту.
- При кожному виклику клієнтом захищається функції перевіряти, чи має даний клієнт необхідний для її виклику набір прав.
Тепер настав час розглянути кожен з етапів окремо. Ми це будемо робити, спираючись на код додається до статті приклад.
Зауваження: Для підвищення наочності в публікованих тут цитатах коду повністю опущена вся обробка помилок. У реальності, звичайно ж, так чинити не можна, і в самому доданому прикладі така обробка присутня.
Етап перший. Що будемо захищати?
Для реалізації прикладу до статті мною був обраний досить, на мій погляд, абстрактний об'єкт. Його абрактность, як мені здається, була дуже важливим параметром для демонстрації саме загальних принципів побудови системи, без прив'язки до будь-яких конкретних умов.
Отже, захищати ми будемо набір звичайнісіньких текстових рядків. Сервер буде зберігати цей список набір з дескриптором захисту на диску, завантажувати його при старті і зберігати при завершенні своєї роботи. Для роботи з цим набором сервер буде надавати клієнтам следующии функції:
- Отримання кількості рядків.
- Читання конкретної рядки за індексом.
- Перезапис існуючої рядка.
- Додавання нового рядка.
- Видалення рядка.
Крім того, для адміністрування сервер надає наступні функції:
- Зчитування існуючих установок безпеки.
- Зміна налаштувань захисту.
І тут на питання "що захищати?", Ми відповідаємо - "Все!"
Етап другий. Визначаємося з правами.
Отже, список захищаються функцій у нас є. Тепер на його основі визначимо набір прав для роботи з цими функціями:
У параметрі PrivilegeSet функція поверне Вам набір привілеїв, які нею були розглянуті при прийнятті рішення про надання доступу. У параметрі GrantedAccess функція повідомить, якими саме із запитаних прав має поточний клієнт. А в параметрі AccessStatus Ви отримаєте загальний результат перевірки - дозволено Вам чи ні виконувати всі запитані дії.
Кілька слів про приклад
Доданий до статті приклад включає групу з трьох проектів:
- Сервер AccCtrlSvc.dpr (папка Server)
- Клієнт AcsClient.dpr (папка Client)
- Аплет панелі управління AcsCntl.dpr (папка CPL)
Крім перерахованих, до архіву також входять папки DCU (для DCU-файлів), BIN (сюди потрапляють іполняемие модулі), Shared (тут лежать модулі, які не входять в проекти, але які вживали) і MsgLibrary, що містить окремий проект AcsMsg.dpr, єдине призначення якого - бути контейнером для таблиці повідомлень, що використовується при логгірованіі дій сервера. Треба зауважити, що включена в нього таблиця повідомлень призначена швидше для налагодження сервера, а ніяк не для інформування системного адміністратора, як це повинно бути на практиці. Пояснюється це самим призначенням даного сервера - слугувати навчальним посібником.
Про апплете вже сказано достатньо, про клієнта ж говорити вобщем-то нічого, там все занадто просто. А ось про сервер ще трохи сказати варто.
Сервер виконаний у вигляді служби. При інсталяції він вносить необхідну інформацію до реєстру, при деінсталяції він її видаляє. При першому запуску сервер створює файл ACService.dat в директорії "Application data" користувача Localsystem. При деінсталяції цей файл також видаляється. У цьому файлі сервер зберігає в зашифрованому вигляді дескриптор захисту об'етов і самі дані, що захищається.
В якості транспорту сервер використовує іменовані канали. Вибір їх пояснюється простотою реалізації в поєднанні з легкістю імперсонації клієнта сервером. Крім того, у мене вже була готова реалізація цього транспорту. Правда, в цілях скорочення не відноситься до теми статті коду, код транспорту піддався досить серйозного скорочення. В першу чергу, "під ніж" потрапило все пов'язане з оптимізацією продуктивності. Так-же був до межі спрощено протокол обміну і зведений до жорсткої схемою "запит-відповідь". Все це робить дану реалізацію транспорту малопридатною для використання в реальних проектах, зате він цілком годиться в якості відправної точки для самостійної реалізації Вами такого транспорту.
Якщо Вас зацікавив матеріал даної статті, то для Вас є прямий сенс розширити і поглибити знайомство з цією темою. Для цілей тренування я міг би запропонувати Вам вирішити такі завдання:
- Додати можливість створення об'єктів клієнтами, так щоб сервер підтримував роботу з декількома об'єктами з різними установками захисту.
- Додати підтримку аудиту для Ваших об'єктів.
- Додати підтримку дерева об'єктів з можливістю успадкування налаштувань дочірніми об'єктами.