Подписване на идентификатор на ресурс и сигурност на APIот DDoS атаки

Искам да говоря за някои от констатациите, които направих, след като работих върху един от най-посещаваните уебсайтове в света.

идентификатор

Имах възможност да участвам в този проект като консултант. Посещаемостта на ресурса е около 200 милиона уникални потребители на месец. Подобна популярност означава и високо ниво на рискове за информационната сигурност, по-специално рискът да бъдете подложени на различни видове атаки, най-честата от които е DDoS. Организацията, която няма да назовавам, е внедрила широк набор от решения за предотвратяване на въздействието на подобни атаки върху работата на услугата. Тези защитни системи са доста често срещани. Те се основават на сглобяването на съдържание на крайни възли (CDN, ESI) и използването на многостепенен пасивен кеш.

Този дизайн е добър за осигуряване на стабилна работа на услугата. Въпреки това, изграждането на приложения, които разчитат на пасивен кеш, означава много допълнителна работа за програмните екипи. По-долу ще обсъдим това по-подробно.

Докато работех по проект, открих начин за защита срещу DDoS атаки, който, въпреки че има същите предимства като пасивния кеш, не регулира толкова строго архитектурата на услугите, които са в основата на системата. За него днес и ще бъде обсъдено.

Какво е пасивен кеш?

В тази конфигурация системата за поддържане на кеша е хранилище на данни ключ-стойност (като Redis), а основният източник на данни е система за управление на релационна база данни (като Oracle Database).

Услуга с активен кеш първо се опитва да прочете данните от кеша и ако това не успее, се обръща към основния източник на данни.

Използване на пасивен кеш за DDoS защита

Използване на пасивна кеш архитектурагарантира, че основната услуга с изходните данни никога няма да се натъкне на неочаквано голям обем заявки. Независимо от това колко и какви заявки са направени към услугата, основният източник на данни се използва само от услугата за опашка за съобщения за попълване на хранилището на кеш данни.

Въпросната блог услуга използва активен кеш. Когато клиент поиска статия с индекс „1“, услугата осъществява достъп до кеша и връща резултата или (ако няма запис в кеша за исканата статия), тя осъществява достъп до базата данни, извлича резултата и го съхранява за известно време в кеша.

Ако нападател организира атака, която включва извършване на HTTP заявки за извличане на статия с индекс „1“, всички тези заявки ще бъдат обслужени от хранилището на кеша. Запитването на данни от хранилище на ключ-стойност не изисква много ресурси. За да атакува успешно системата чрез претоварване на подсистемата за търсене в такова хранилище, атакуващият ще се нуждае от много сериозна мощност.

Ситуацията е много различна, ако атаката използва произволни стойности за конструиране на идентификатора на статията, например стойности в диапазона от 1 до 1 милион. Сега всяка заявка ще доведе до необходимост от достъп до основната база данни.

За разлика от търсенето в хранилище ключ-стойност, заявките към релационна база данни изискват много ресурси. Шансовете са добри, че пакетите заявка/отговор ще трябва да преминат през много по-голям брой възли, също така е възможно отговорът да трябва да бъде обработен с помощта на логиката на приложението, резултатите да бъдат кеширани и т.н.

Мащабирането на съхранение на ключ-стойност е бързо и евтино, което не е случаят с мащабирането на системата за управлениерелационни бази данни.

Ако услугата използва пасивен кеш, тогава проблемите с мащабирането са ограничени до нея. Архитектурата на пасивния кеш е проектирана да увеличава мощността на кеша бързо и лесно. Тази архитектура обаче усложнява развитието.

Разработване на услуги, които използват пасивен кеш

Когато създавате услуга, която използва пасивен кеш, трябва да имате предвид няколко изисквания.

  • Първо, данните могат да се четат само от кеша.
  • Второ, след всяка операция за създаване, актуализиране или изтриване на данни, поискани от услугата, тя трябва да постави съответната задача в опашката от заявки към хранилището на изходните данни.
  • Трето, след всяка задача за създаване, актуализиране или изтриване на данни, извършена върху данните на основното хранилище, услугата трябва да постави на опашка задача за актуализиране на съответните секции на кеша.
Всяка CRUD операция на системата трябва да бъде внедрена, като се вземат предвид горните ограничения.

По време на разработката времето между искането за извършване на някаква операция и получаването на резултата се увеличава поради наличието на опашка със задачи. Това забавя процеса на разработка и тестване. Освен това програмистът трябва да е наясно със специфични грешки, които могат да възникнат поради остарели данни в кеша.

От друга страна, по време на разработването на приложение, което използва активен кеш, програмистът може просто да деактивира кеша по време на работа, постигайки много висока скорост на обработка на произволни заявки към основното хранилище на данни.

Проектирането на системи, които използват пасивен кеш, е по-трудно, но когато сигурността е на първо място, такива сложности обикновено се игнорират. Това обаче не означава, че всички методи за защита срещу DDoS атакисъс сигурност ще изисква големи усилия. По-горе разгледахме пример за атака срещу блог услуга чрез изброяване на идентификатори на статии. Можете да смекчите ефектите от такива атаки, като направите идентификаторите на ресурси непредвидими.

Идентификатори на ресурс за подписване

Причината, поради която кеш-активните системи са податливи на атаките, описани по-горе, е, че атакуващият може лесно да създаде идентификатор на ресурс. Независимо дали идентификаторът е числов идентификатор (като в нашия пример), кодиран с base64 GUID, както в GraphQL API, или UUID, както в повечето бази данни, базирани на документи, проблемът е, че когато сървърът получи заявка, той не знае дали исканият ресурс съществува. Единственият начин да разберете е да направите повикване към кеша или основния източник на данни и да изчакате отговор. За да може сървърът да определи дали исканият ресурс съществува, без да пита нищо, идентификаторите на ресурсите могат да бъдат подписани.

Подписването позволява, без сериозно въздействие върху производителността на системата, да разберете дали заявката е правилно оформена. Ако идентификаторът на ресурса е подписан, атакуващият няма да може да прави заявки за идентификатори, които не са част от ограничения набор от публични идентификатори.

Всичко работи по следния начин: услугата получава заявка и се опитва да дешифрира идентификатора на ресурса. Ако успее, дешифрираната стойност се използва за намиране на искания запис. Ако идентификаторът не може да бъде дешифриран, обработката на заявката приключва.

Използвам този подход, когато създавам идентификатори на ресурси на GraphQL. По-специално, проксито, което пренасочва GraphQL заявките, първо проверява дали идентификаторът на ресурса е валиден.

Подписан GUID илиsguid е пакт за Node.js, в който съм извадил процедурите за създаване и проверка на подписани идентификатори. Можете да подпишете идентификатор с помощта на командата toSguid. Командата fromSguid се използва за проверка и отваряне на подписани идентификатори. Изглежда така:

В допълнение към идентификаторите за подписване, Sguid е проектиран да използва пространства от имена и идентификатори за типове ресурси. Това гарантира, че идентификаторите са глобално уникални.

Sguid използва криптосистемата с публичен ключ Ed25519. Полученият подпис е кодиран с помощта на base64 URL кодиране.

Недостатъкът на този подход са идентификаторите, които са неудобни за използване от хората:

Плюс - мащабируема защита срещу DDoS атаки, провеждани на приложния слой на OSI модела, без да усложнява прекалено процеса на разработка.

Трябва да се отбележи, че описаната тук техника изобщо не помага за защита срещу атаки, насочени към препълване на комуникационните канали. Освен това, той е ефективен само ако кешът може да съхранява данни за всички значими заявки. Но въпреки тези ограничения, това е полезен подход за защита срещу пропускащи атаки на сървърния кеш.

Освен това трябва да помним, че в случай на защита срещу кибератаки е важно как изглеждат резултатите от атаката от гледна точка на нападателя. За да се „пробие“ една ефективно проектирана система, като се използва подходът, описан тук, чрез повторение на идентификатори на ресурси, е необходима сериозна мощност. Може би нападателят просто не разчита на това и виждайки, че системата не реагира на неговите действия (въпреки че може да работи на границата на възможностите си), той ще реши, че вече е опитал всичко възможно и ще спре атаката.