Статья для участия в конкурсе Тестирование Веб-Приложений на проникновение.
Часть 1 - [Истории за кодом] Притча о тривиальности. Брутфорс атака.Доброго времени суток, codeby, продолжаем разговор, начнём сразу с практики, с того на чём остановились в прошлый раз.
Presentation Layer. Честно сказать, всё-таки я не определился с вопросом о том, что у нас будет в итоге: консольное приложение, web spa application или вообще оконный интерфейс. Но этот факт, лишь подтверждает, что у нас уже получилась хорошая архитектура. Так как хорошая архитектура позволяет откладывать решения как можно дольше! Действительно, как бы то не было, пользовательский интерфейс мы можем делать каким угодно, в итоге мы просто будем обрабатывать информацию от пользователя и передавать её нашему слою с бизнес логикой. Поэтому пока давайте обойдёмся unit и интеграционными тестами, а интерфейс напишем, когда решим.
Итак, дорогие, мы получили достаточно хорошую архитектуру:
- Она легко масштабируется:
- За счёт DI-техник мы получили слабосвязанные слои приложения, которые можно менять независимо друг от друга.
- Теперь для того, чтоб добавить новую функциональность в приложение у нас есть достаточно чёткий алгоритм действий, достаточно сделать себе чек-лист чтоб не путаться, в дальнейшем всё это будет уже на автомате.
- Применяя SOLID принципы к нашим классам, мы продолжим поддерживать чистую архитектуру и код.
- За счёт нашего архитектурного решения – приложение легко тестировать, что мы увидим в дальнейшем на примере. У нас будет код, поведение которого мы можем проверить «от сих до сих», а за счёт того, что тесты будут автоматизированными мы не пропустим неожиданных поломок, что несравненно скажется на скорости разработки.
- Мы можем выбрать абсолютно любую базу данных, так как мы не завязаны ни на реляционных ни на nosql. Мы вообще распоряжаемся своими моделями на каждом уровне, которые пишем сами.
- При соблюдении общего подхода к добавлению функциональности мы легко можем работать в команде в параллель и особо не конфликтовать (в изменениях) друг с другом. (оффтоп: когда хотел писать курс для школы codeby, собирался пустить какое-нибудь такое приложение в качестве стажировки для своих… Кто знает может ещё всё впереди)
Создадим новую базу данных и сразу переключимся на неё. Я использую SQL Operations Studio, для работы с базами.
Далее сделаем таблицу для хранения словаря
Особо пока не заворачиваемся с ограничениями. Заполним данными.
3 не валидных и один валидный пароль (исключительно для чистоты эксперимента)
Настраиваем EF. Для начала создадим папку DB в ForAticle.DataAccessLayer. Далее добавим новый предмет. RightClick по папке, добавляем ADO.NET Entity Data Model, называем ForArticle.DataBaseModel
Далее выбираем способ подключения
Дальше всё просто, подключаемся к sql серверу (он должен быть установлен) выбираем нашу таблицу и в результате у нас будет edmx модель, контекст и прочие прелести.
Далее напишем реализацию интерфейса IBruteForceDictionaryHandler назовём её просто BruteForceDictionaryHandler. В ней определим метод фрагментированного чтения
Поменяем зависимость ServicesDependencies
было
Стало
Вот мы и переписали часть приложения с файловой системы на базу данных.
Теперь давайте остановимся и подумаем. Специфика работы с базой данных подразумевает определенный алгоритм, который будет неизменен:
- Открыть соединение с базой данных
- Выполнить действия
- Закрыть соединение с базой данных
В проекте DataAcessLayer в папке Interfaces создадим папку Base, где и будем создавать абстракции. Первым делом опредеилим интерфейс IDataContextHandler
Этот интерфейс будут реализовывать все интерфейсы наших обработчиков. Так же напишем базовый абстрактный класс для наших обработчиков - DataContextHandlerBase.
Теперь сделаем интерфейс для процесса исполнения обработчика.
И класс
Поле _kernel с типом IKernel нужно для разрешение зависимостей, дальше объясню. В методах Do и DoWithTransaction происходит инкапсуляция основного алгоритма, описанного мной выше для работы с бд. Вот так они выглядят:
Мы открываем соединение с базой данных. Выполняем действия из Handlera, затем возвращаем результат. Кроме того, в дальнейшем тут будет входная точка для подключения логера.
Теперь напишем базовый класс для всех сервисов.
Внимание на метод Exec и ExecWithTransaction. Про оператор using: это такой синтаксический сахар, для классов реализующих IDisposable. После закрывающей фигурной скобки выполняется вызов Dispose для объекта созданного в using, в этом методе мы высвобождаем занятые ресурсы. Напомню, что Dispose для DataContextHandlerProcess выглядит следующим образом
Т.е. мы таким образом закрываем соединение. Перепишем класс BruteForceDictionaryService следующим образом.
На строке 13 мы прокидываем kernel для разрешения зависимости в вниз по иерархии. На строке 17 мы вызываем метод Exec из базового класса, которому передаём делегат, который будет выполняется в контексте класса DataContextHandlerProccess. Вызовом p.GetHandler<T>() мы инициализируем обработчик данных BruteForceDictionaryHandler. Далее на строке 18 мы получаем словарь из бд. На строке 20 переводим этот словарь в объект DTO и приводим к коллекции методом ToList. Делегат для метода Exec закончил своё выполнение, а значит вызовется метод Dispose, который закроет соединение с бд. Все живы и здоровы.
В следующий статье:
- Определимся с интерфейсом ( у нас будет web spa приложение на react+redux) покажу как использовать webpack и еже с ним. Напишим компоненты: тулбар, основное меню, таблицу и диалог на добавления\редактирования сущностей нашей системы.
- Начнём писать тз для нашего приложения.
- Сделаем сервис по определению столбцов через union в уже упомянутой уязвимости на rootme.
- Наконец появится ссылка на gitlab с тасками, которые вы сможете брать, для практики.
- Заменим DI-контейнер на TiniIOC, вследствие чего произведём необходимый рефакторинг.
Последнее редактирование: