Как жить с WAF, чтобы не было мучительно больно

z29mo7n0jla220e_3i8tr8yl4ii.png
Здесь не будет очередной статьи, описывающей возможности межсетевого экрана уровня приложений. Таких уже полно. Сегодня мы будем объяснять подводные камни при работе с этим решением, чтобы вы знали о них еще до старта проекта и правильно прокладывали курс.
Впервые про Web Application Firewall (WAF) на отечественном рынке заговорили в 2008 году, а серьезную популярность он приобрел в 2011. Решение на текущий момент довольно-таки востребованное, однако никто толком не знает, зачем оно ему нужно (до первого инцидента). При общении с подразделениями информационной безопасности различных организаций мы чаще всего слышим: «Да кому мы нужны» и «Нас раньше не взламывали и сейчас не взломают». Однако, как показывает практика, атакуют всех, автоматизированно и порой таргетированно.

Хакеры — это своеобразное комьюнити, которое, как и любое другое, состоит из неофитов и профессионалов. У любителей на этом поприще мотив только один — найти уязвимость и похвастаться этим, что для них уже само по себе награда. Кто поумнее, продает эту информацию в даркнете. Там она попадает в руки весьма профессиональных кибергруппировок, организующих целенаправленные атаки, которые без подготовки задетектировать практически невозможно. Ранее в своих статьях мы уже говорили, что злоумышленники все чаще стремятся к долгосрочному и незаметному присутствию в уязвимой инфраструктуре с целью детального исследования и получения как можно более полного доступа к информационным и технологическим системам.

Последствия взлома могут быть разными, от кражи денег с расчетных счетов до использования ресурсов организации в проведении DDoS-атак (и рисков, что в этом вам же предъявят обвинение).

Заказчики, которые приходят к нам за сервисами WAF Solar MSS, рассказывают об одних и тех же проблемах, с которыми сами столкнулись при внедрении и которые не были столь очевидны «на берегу».

Закладывайте дополнительный бюджет


К счастью, закупку решений для защиты веб-приложений в последнее время стало легче обосновать в бюджете. И вот вы уже счастливый обладатель одного из WAF, которые существуют на рынке, возможно даже не самого плохого… Однако достаточно открыть инструкцию, чтобы понять, что без подготовленных должным образом специалистов WAF не настроить и от злоумышленников не защититься, а блок ИТ не спешит выделять администраторов на его эксплуатацию.

Допустим, вы отправляете сотрудника на обучение работе с этим устройством (кстати, многие отправляют на такое обучение самых молодых и неопытных подчиненных — большая ошибка). Специалист возвращается через пару дней и начинает вместе с ИТ-администраторами настраивать сетевую связанность веб-сервера и WAF (хотя на самом деле вся эта работа обычно сводится к изменению дефолтных маршрутов и перенаправлению трафика через WAF). И вот все ключи и сертификаты уже на WAF, SSL-трафик вовсю инспектируется, но одновременно половина функционала сайта перестает работать. Прекрасные модули защиты WAF решили, что JavaScript«ы на сайте работают как вредонос или как боты, CSRF-токен, как выясняется, должен запрашиваться не везде, но откуда это вам WAF было знать.

r669fmrwwhkmhk8mh0vffpih5ps.jpeg

Далее вы видите на дашбордах разные цифры напротив слов «low», «medium», «high», какие-то обученные 10 моделей машинного обучения уже готовы вступить в работу, только дай им волю, а что с этим дальше делать, никто не знает, и ваш обученный специалист в том числе. Потому что за два дня невозможно обучить профилированию под конкретную систему WAF, дать настолько глубокое представление о всех разновидностях типовых и нетиповых атак OWASP, чтобы специалист мог определить, актуальны ли они для веб-приложений его компании, а тем более научить корректировать под них настройки WAF.

А ведь ещё надо понимать, какие события должны формироваться в инцидент и как адаптировать правила корреляции под конкретное на веб-приложение. Если в бюджет была заложена только стоимость самого решения, на привлечение интегратора, который помог бы его настроить, денег часто уже нет, поэтому чаще всего WAF кладут на полку переводят в режим работы по span-порту, меняют сетевые маршруты на дефолтные и откладывают работы на следующий год, когда появится новый бюджет.

Попутно многие узнают, что WAF не всегда стабилен 24×7 и частенько падает, из-за чего могут случаться простои в доступности веба. Нужен отказоустойчивый кластер, нужно постоянно мониторить его службы и доступность веб-приложения. Все это лучше учесть и заложить в бюджет «на берегу».

Оцените, сможете ли вы самостоятельно писать политики и реализовывать интеграцию


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

Но когда выйдет новый мажорный релиз вашего веб-приложения, всё эти политики превратятся в тыкву, так как они были созданы для предыдущей версии, а новый функционал может просто не работать через WAF.

Кроме того, под некоторые задачи по защите веб-приложений лучше использовать отдельные классы СЗИ, например, Anti-DDoS или SIEM, и значит, WAF надо будет с ними интегрировать. Это тоже не тривиальная задача — надо понять, какие данные, как и в каком формате нужно отсылать на эти внешние системы, так как СЗИ не всегда может самостоятельно распарсить сообщения с WAF.

Так, например, у одного из наших заказчиков была задача фиксировать неудачные попытки аутентификации на WAF, чтобы в дальнейшем пересылать эти события в SIEM и мониторить на наличие атак типа bruteforce. Такие правила обычно реализованы во всех популярных WAF и отрабатывают без дополнительных корректировок. Однако разработчики веб-приложения заказчика написали логику аутентификации таким образом, что форма авторизации при отсылке выглядела как массив в массиве — нестандартно для формы авторизации и для WAF«ов. Обработать штатными правилами WAF такою форму запроса на наличие атак типа bruteforce было невозможно. Мы создали кастомное правило, которое отслеживало количество попыток аутентификации, формат, в котором была отправлена форма, код сервера и тело ответа, в котором парсилось значение успешной или неуспешной аутентификации. Помимо прочего, правило должно было содержать защиту от ботов: если количество аутентификаций превышало задаваемый порог, то в страницу ответа вписывался скрипт, который проверял запросы в сторону сервера на «человечность». Если следующий запрос в сторону сервера не проходил эту проверку, то клиента редиректило на страницу с капчей. Также это правило не должно было мешать работе легитимной активности ботов (Yandex, Google и т. д.).

Пример реализации
when CLIENT_ACCEPTED {
  BOTDEFENSE::disable
  set loginevent 0
  set srcip2 [IP::remote_addr]
  set coun222t 0
  set login_count 3
  set countloginintable 0
  set user_agent 0
  set var test
}

when HTTP_REQUEST {
set sms_count 3
	set evil_client 0
    set evil_client_action 0
	set b_challande_count 0
	 set user_agent [HTTP::header User-Agent]
    set var [IP::client_addr]$user_agent
	if {[virtual name] == "vs_ccc_pilot"} {
#####START LK########
 if { ([HTTP::path] starts_with "/login") and [HTTP::method] eq "POST"} {
    HTTP::collect [HTTP::header Content-Length]
    set loginevent 1
    

	
   #log local0. "Login event $loginevent "
 }
  if { ([HTTP::path] eq "/NCbf5" ) && [table keys -subtable customer_login:[IP::client_addr] -count] >= $login_count } {
   set evil_client 1
   BOTDEFENSE::enable
 if { [table keys -subtable customer_login_un:$var -count] >= 3  } {
	 set evil_client_action 1
	 }
   
 }
  if { ([HTTP::path] eq "/NCbf5" ) && [table keys -subtable customer_login:[IP::client_addr] -count] < $login_count } {
  HTTP::redirect "/login"
  }

#####END_LK########

#####START_SMS########
 if { ([HTTP::path] starts_with "/somebuilder/somepath/someVerification/sendsomesms.json.jsp") and [HTTP::method] eq "POST"} {
    HTTP::collect [HTTP::header Content-Length]
    set loginevent 2
    set SMS_count 3
	set b_challande_count_sms 0
   #log local0. "Login event loginevent "
 }
#####END_SMS########


}
}

when HTTP_REQUEST_DATA {
###разбор запроса###
  if { $loginevent == 1 } { 
                             foreach x [split [string tolower [HTTP::payload]] "&"] {
				if { $x starts_with "%2fcom%2fsomesite%2fsomeuserprofil%2floginhandler.loginsensitive=" } { 
                      set user_agent [HTTP::header User-Agent]
                     set var [IP::client_addr]$user_agent
				     set username [lindex [split $x "="] 1]
				     set countloginintable [table keys -subtable customer_login:[IP::client_addr] -count]
				     set countloginintable2 [table keys -subtable customer_login_un:$var -count]
				    
                     if { [table keys -subtable customer_login:[IP::client_addr] -count] >= $login_count  } {
                         set evil_client 1
						 set srcip [IP::remote_addr]
						 set msec [clock clicks -milliseconds] 
						
						 
						 if { [table keys -subtable customer_login_un:$var -count] >= 3  } {
						 
						 set evil_client_action 1
						 } else { 
						 table set -subtable customer_login_un:$var $msec indefinite  600
						 }
                         BOTDEFENSE::enable

                        }
					}

				}
###разбор запроса###
   log local0. "USERNAME $username count $countloginintable count capt $countloginintable2 var $var"
    HTTP::release
  }    elseif { $loginevent == 2 } { 
                             foreach x [split [string tolower [HTTP::payload]] "&"] {
				if { $x starts_with "phone=" } { 
				     set phone [lindex [split $x "="] 1]
					 table set -subtable sms_some_phone:[IP::client_addr] $phone indefinite  600
                     if { [table keys -subtable sms_some_phone:[IP::client_addr] -count] >= $sms_count  } {
                         set evil_client 2
						 set srcip [IP::remote_addr]
                         BOTDEFENSE::enable

                        }
					}

				}

   log local0. "phone sms $phone "
    HTTP::release
  } 
  
}

###проверка корректности аутентификации###

when HTTP_RESPONSE  {
        if { $loginevent == 1 } { 
        HTTP::collect 2048
        if { [HTTP::cookie exists "SOME_USER_ID"] } {
        log local0. "successsss login $username $success_login Evilclient $evil_client "

            set success_login 1
        } else {
            set success_login 0
                    log local0. "asdasdassuccesssss login $username $success_login Evilclient $evil_client "

		table set -subtable customer_login:[IP::client_addr] $username indefinite  600
        }
        set loginevent 0
			log local0. "success login $username $success_login Evilclient $evil_client "
        }

}

 when BOTDEFENSE_ACTION {
 
  log local0. "BOTDEFENSE_ACTION [BOTDEFENSE::action] client $evil_client BR [BOTDEFENSE::reason]  BC [BOTDEFENSE::captcha_status] $evil_client_action"
    set coun222t 0
	set key "$srcip2"
	append key "_8"
	 if {[HTTP::path] eq "/NCbf5" and $evil_client == 1 and  [HTTP::method] eq "GET" and not ([BOTDEFENSE::action] eq "allow") } {
	
	if { ($evil_client == 1  and $evil_client_action == 0) and (not ([BOTDEFENSE::reason] starts_with "passed browser challenge")) and ([BOTDEFENSE::captcha_status] ne "correct") } {

	log local0. "[IP::client_addr] has [BOTDEFENSE::action], reason: [BOTDEFENSE::reason]"
	#Browser Chalange
	set res [BOTDEFENSE::action browser_challenge]

			} elseif { ($evil_client == 1  and $evil_client_action == 1)  and (not ([BOTDEFENSE::reason] starts_with "passed browser challenge")) and ([BOTDEFENSE::captcha_status] ne "correct")  }  {
		    	set res [BOTDEFENSE::action captcha_challenge]
			      log local0. "[IP::client_addr] has [BOTDEFENSE::action], reason: [BOTDEFENSE::reason]"

			} else { set res [BOTDEFENSE::action allow] }
			
	} elseif  	{[HTTP::path] eq "/login" and $evil_client == 1 and  [HTTP::method] eq "POST" and (not ([BOTDEFENSE::reason] starts_with "passed browser challenge")) and ([BOTDEFENSE::captcha_status] ne "correct") and not ([BOTDEFENSE::action] eq "allow") } {
		BOTDEFENSE::action custom_redirect "/NCbf5" 302
		log local0. "Send custum redirect [IP::client_addr]"
	
	} elseif  	{[HTTP::path] eq "/NCbf5"  and [BOTDEFENSE::action] eq "allow" } {
		BOTDEFENSE::action custom_redirect "/login" 302
		log local0. "Send custum redirect [IP::client_addr]"
	
	} 
			
 
 }


Такое правило позволило заказчику отслеживать события, связанные с подбором логинов/паролей, даже с учетом особенностей его формы авторизации.

Помните, что защита веб-приложений — непрерывный процесс


А ещё бывают такие ситуации, когда появляется информация о новой уязвимости, а вендор ещё не прислал обновления, чтобы WAF начал ее детектировать и закрывать. Разработчики уязвимого ПО тоже ещё ничего обновить не успели. Вспомните ShellShock: тогда миллионы систем разом стали уязвимыми, а реализовать атаку было настолько просто, что с этим справился бы и «скрипткидди». А атаковать начали с первых часов после публикации новости о найденной уязвимости. И что в этом случае делать? Пытаться профилировать политики под эту уязвимость бесполезно, нет сигнатурной базы.

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

Работа с WAF предполагает постоянное взаимодействие со всеми структурными подразделениями, которые отвечают за работу веб-сервера и располагающихся на нём веб-приложений. Работа с WAF — это постоянная эксплуатация и адаптация существующих политик безопасности, это работа в режиме 24×7 для поддержки доступности и реагирования на возникающие инциденты, это наличие штата опытных специалистов и аналитиков, которые отлично понимают отличие XSS от SQL-инъекций, понимают, что актуально для одного веб-приложения и не применимо для другого, понимают принцип работы разных фреймворков и могут провести качественную и быструю адаптацию профиля и политик безопасности на WAF под конкретное веб-приложение. Подробнее мы писали об этом в статьях «Проблема непрерывной защиты веб-приложений», где давали взгляд на проблему со стороны разработчиков и заказчиков.

Возможно, после прочтения статьи кому-то расхочется вообще связываться с WAF, но в современных реалиях такой подход уже почти невозможен. Просто с самого старта проекта держите в голове все особенности эксплуатации и планируйте, как вы будете обходить эти подводные камни.

Егор Валов, аналитик отдела экспертного пресэйла продуктов и сервисов Solar JSOC

© Habrahabr.ru