Запрос межсайтовое подлог (CSRF) происходит , когда хакер использует тот факт , что пользователи не всегда выходите из веб — сайтов и веб — приложений , которые они посещают. Хакер создает на веб-сайте, которым он управляет, URL-адрес или форму, которая передает действительные данные в действительное место назначения на целевом веб-сайте, и надеется, что пользователь, который все еще проходит проверку подлинности на этом целевом веб-сайте, щелкает этот вредоносный URL-адрес или форму. Если такой пользователь попадет в ловушку, целевой веб-сайт обработает запрос так же, как если бы пользователь выполнил действие на целевом веб-сайте при нормальных обстоятельствах.
Одним из распространенных методов предотвращения CSRF-атак является создание уникального значения каждый раз, когда пользователь посещает форму на веб-сайте, и сохранение этого значения как в сеансе пользователя, так и в самой форме в виде скрытого поля. Когда форма отправляется, значение в форме сравнивается со значением, сохраненным в сеансе пользователя, и, если они не совпадают, отправка формы не обрабатывается. В следующий раз, когда пользователь встречает форму (даже если это та же форма), генерируется новое уникальное значение. Без возможности узнать, что это уникальное значение в любой момент времени, хакер не может создать форму или создать URL, который имитирует законный запрос, и атака завершается неудачей.
Вместо того, чтобы не забывать создавать эти уникальные значения и включать их в каждую форму (или в каждый URL, который выполнил какую-то операцию с данными), а затем проверять достоверность отправленного значения на каждой странице обработки, я хотел бы увидеть, было ли способ, которым я мог бы встроить защиту CSRF в структуру моих приложений Model-Glue.
Во-первых, я написал две новые функции контроллера в моем контроллере аутентификации / авторизации CFC:
<cffunction name="secureTransmissionURL" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> <cfif arguments.event.valueExists("token") EQ false> <cfset session.token= CreateUUID()> </cfif> <cfset arguments.event.setValue("secureMyself","index.cfm?token=" & Hash(session.token,"SHA-256") & "&" & arguments.event.getValue("eventValue") & "=")> </cffunction> <cffunction name="validateTransmissionURL" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> <cfif arguments.event.valueExists("token") EQ false> <cfset arguments.event.setValue("validationProblem","noToken")> <cfset arguments.event.addResult("invalidTransmission")> <cfelseif arguments.event.getValue("token") NEQ Hash(session.token,"SHA-256")> <cfset arguments.event.setValue("validationProblem","tokenMismatch")> <cfset arguments.event.addResult("invalidTransmission")> </cfif> </cffunction>
Функция secureTransmissionURL () проверяет, есть ли переменная с именем «token», хранящаяся в объекте события (для тех, кто не знаком с Model-Glue, объект события служит контейнером для всех переменных, связанных с запросом, включая форму и переменные URL). Если переменная токена не существует в реквете, переменная с именем «токен» создается или обновляется в рамках сеанса и получает уникальное значение UUID.
В последней строке функции secureTransmissionURL () в объекте события создается новая переменная «secureMyself», которой присваивается значение, которое служит отправной точкой для любого URL-адреса, который я хочу защитить от атак CSRF внутри моей модели. Нанесение клея. Эта строка заслуживает немного справочной информации …
В Model-Glue (как и во многих средах ColdFusion) все запросы выполняются через страницу index.cfm, и вы определяете, как запрос должен быть перенаправлен, добавляя определенную переменную (называемую переменной «eventValue» в Model-Glue) на URL. В Model-Glue именем этой переменной по умолчанию является «событие», поэтому, если вы оставите это значение по умолчанию, URL-адреса, которые вы будете использовать для навигации в приложении Model-Glue, будут выглядеть следующим образом:
index.cfm?event=deleteRecord&recordId=12
Поскольку можно изменить это имя переменной eventValue с «event» на что-то другое («action», «goto» и т. Д.), Просто изменив настройки конфигурации Model-Glue в своем приложении, жестко программировать небезопасно «index.cfm? event =» в ваши URL на ваших страницах. Таким образом, стандартная практика заключается в использовании переменной события, автоматически предоставляемой Model-Glue под названием «я», для создания ваших URL. Поэтому вместо того, чтобы писать «index.cfm? Event = mainMenu», вы должны сделать что-то подобное на своей веб-странице:
<cfset deleteRecordURL= event.getValue("myself") & "deleteRecord"> <cfoutput> ... <a href="#deleteRecordURL#&recordId=12">Delete record 12</a> ... </cfoutput>
(Примечание: обычно имя обработчика события / события, в данном случае «deleteRecord», на самом деле также берется из переменной события, но я хотел, чтобы мой пример был простым)
Переменная «secureMyself», созданная в этой последней строке secureTransmissionURL (), служит защищенной CSRF альтернативой переменной «себе», предоставляемой Model-Glue. Он добавляет хешированное значение UUID, хранящееся в области сеанса, к переменной URL-адреса «токен» перед переменной eventValue в строке URL-адреса, что позволяет мне использовать «secureMyself» для создания своих URL-адресов вместо «я», где необходимо (примечание: я все еще использовал бы «себя» для создания URL-адресов, которые не обрабатывают данные напрямую, например URL-адрес, который отправил пользователя на страницу меню):
<cfset deleteRecordURL= event.getValue("secureMyself") & "deleteRecord"> <cfoutput> ... <a href="#deleteRecordURL#&recordId=12">Delete record 12</a> ... </cfoutput>
Когда ColdFusion отображает защищенный URL-адрес, он выглядит примерно так:
index.cfm?token=524606212847B725A8AD313DD466CDCF66F8FC22B49DC31D525D51FC33B1E297&event=deleteRecord&recordId=12
Вторая функция validateTransmissionURL () предназначена для выполнения до обработки запроса страницы, защищенного CSRF. Он проверяет, была ли переменная токена включена в запрос, и если да, то проверяет, соответствует ли значение переданного токена хешированному значению переменной токена, сохраненной в сеансе. Если любое из этих условий не выполняется, результат «invalidTransmission» добавляется к объекту события, что эффективно предотвращает переход запроса к коду, который обрабатывает запрос (который взаимодействует с вашими постоянными данными).
После добавления этих двух функций я включил их в свое приложение, используя следующие два типа событий:
<event-types> <event-type name="permitted"> <before> <broadcasts> <message name="checkAuthorization" /> <message name="secureTransmissionURL" /> </broadcasts> <results> ...<!--Whatever you do if user is not authenticated yet--> </results> </before> </event-type> <event-type name="validateTransmission"> <before> <broadcasts> <message name="validateTransmissionURL" /> </broadcasts> <results> <result name="invalidTransmission" append="validationProblem" do="invalidTransmission" redirect="true" /> </results> </before> </event-type> </event-types>
Если вы не знакомы с типами событий в Model-Glue, я рекомендую вам прочитать документацию на вики-сайте Model-Glue . В моем приложении все мои обработчики событий, которые доступны пользователю только после того, как они аутентифицировались / вошли в систему, заключены в «разрешенный» тип события, определенный выше. Добавляя широковещательную рассылку сообщений, которая вызывает мою функцию контроллера secureTransmissionURL () для этого типа события, я гарантирую, что переменная события «secureMyself» доступна для использования на всех моих страницах просмотра с проверкой подлинности.
Тип события «validateTransmission», который гарантирует, что представленный URL-адрес содержит правильное значение токена, будет применяться только к моим обработчикам событий, которые обрабатывают отправку формы или выполняют транзакцию базы данных на основе переменных URL-адреса, отправленных в запросе. Если токен отсутствует или неверен, Model-Glue перенаправляет действие в обработчик событий invalidTransmission, который будет реагировать на возможную атаку CSRF. Мой обработчик события invalidTransmission представляет обычное сообщение об ошибке пользователю (поскольку пользователь, а не хакер увидит результат атаки), но уведомляет меня о возможной атаке CSRF.
После того, как у меня были эти функции контроллера и типы событий, все, что мне нужно было сделать, чтобы защитить свои формы и гиперссылки от CSRF-атак, — это использовать переменную события secureMyself, чтобы создать URL-адреса для этих форм и гиперссылок и добавить тип события «validateTransmission» тем обработчикам событий, которые обрабатывали представления из этих форм и гиперссылок.
Если вы хотите узнать больше о защите от CSRF-атак, я бы порекомендовал вам прочитать некоторые посты в блоге, которые помогли мне понять CSRF-атаки:
http://shiflett.org/articles/cross-site-request-forgeries
http://www.mollerus.net/tom/blog/2009/01/an_easy_block_for_crosssite_request_forgeries_csrf.html
http://www.12robots.com/index.cfm/2008/8/25/Request-Forgeries-and-ColdFusion—Security-Series-9
http://www.12robots.com/index.cfm/2009/2/9/Enhancing-Request-Forgery-Protection—Security-Series-91