Double submit что это в тестировании
Множественные submit для формы
С приходом HTML5 формы сталее более универсальными. Элемент input теперь может содержать электронные адреса, даты и много другое, их можно отмечать как обязательные не прибегая к javascript – и это всего лишь некоторые из наиболее ценных возможностей. Также теперь для одной формы можно задействовать несколько submit кнопок, а также теперь есть возможность вынести кнопку submit за пределы формы.
Несколько submit внутри одной формы
До недавнего времени в форму можно было вставить только одну кнопку submit, в противном случае форма обрабатывала только последнюю кнопку. Добавляя method=»post» и url к элементу формы «form» мы получали рабочую форму.
Теперь ситуация изменилась – в HTML добавили новые свойства «formmethod» и «formaction». Они позволяют добавить метод post и url непосредственно в кнопку «submit», таким образом к form ничего дописывать не нужно. Имея эти параметры, прикрепленные к кнопке «submit», а не к form – все это добавляет больше гибкости форме. Теперь можно сделать столько кнопок, сколько будет необходимо для формы.
Теперь каждая кнопка «submit» относится к разным url и все это избавляет от того, что при верстке необходимо писать javascript код. Все это отлично работает и теперь по нажатии на какую-нибудь кнопку форма получит formmethod и formaction, которые перезапишут стандартные параметры method и action. Если в форме будет присутствовать обычная кнопка «submit» без новых параметров, то он вернет форме значения, установленные для элемента form.
Свойства formmethod и formaction поддерживаются всеми популярными браузерами
Элементы формы (input, select, textarea) за пределами формы
Общепринятый факт, что все элементы формы, принадлежащие ей должны находится внутри элемента
На сегодняшний день аттрибут form поддерживается всеми популярными браузерами, за исключением Internet Explorer (вплоть до 10й версии).
Методы защиты от CSRF-атаки
Что такое CSRF атака?
Ознакомиться с самой идеей атаки CSRF можно на классических ресурсах:
Выдержка из ответа на SO:
Как от нее защититься?
Эффективным и общепринятым на сегодня способом защиты от CSRF-Атаки является токен. Под токеном имеется в виду случайный набор байт, который сервер передает клиенту, а клиент возвращает серверу.
Защита сводится к проверке токена, который сгенерировал сервер, и токена, который прислал пользователь.
А что, собственно, защищать?
На Habrahabr опубликована статья от Yandex, в которой описано, почему писать свои сервисы нужно, руководствуясь стандартом.
Требования к токену:
На первом MeetUp’е PDUG Тимур Юнусов (руководитель отдела безопасности банковских
систем Positive Technologies) рассказывал, почему именно такие требования предъявляются к CSRF-Токену и чем грозит пренебрежение ими.
Требования к Web-Сервису и окружению:
Отсутствие XSS уязвимостей
Внедренный злоумышленником скрипт имеет возможность отправлять запрос к серверу от имени пользователя и читать его без каких-либо препятствий.
Таким образом, XSS уязвимости могут быть использованы для получения текущего токена.
Отсутствие malware на машине клиента
Если злоумышленник имеет возможность запускать софт на машине клиента, то он может получить любые данные, имеющиеся в браузере.
Методы защиты
Существует 3 метода использования токенов для защиты web-сервисов от CSRF атак:
Synchronizer Tokens
Простой подход, использующийся повсеместно. Требует хранения токена на стороне сервера.
При старте сессии на стороне сервера генерируется токен.
Токен кладется в хранилище данных сессии (т.е. сохраняется на стороне сервера для последующей проверки)
В ответ на запрос (который стартовал сессию) клиенту возвращается токен.
Если рендеринг происходит на сервере, то токен может возвращаться внутри HTML, как, например, одно из полей формы, или внутри тега.
В случае, если ответ возвращается для JS приложения, токен можно передавать в header (часто для этого используют X-CSRF-Token )
При последующих запросах клиент обязан передать токен серверу для проверки.
При рендере контента сервером токен принято возвращать внутри POST данных формы.
JS приложения обычно присылают XHR запросы с header ( X-CSRF-Token ), содержащим токен.
Если оба токена совпадают, то запрос не подвергся CSRF-Атаке, в ином случае — логируем событие и отклоняем запрос.
На выходе имеем:
Защита от CSRF на хорошем уровне
Токен обновляется только при пересоздании сессии, а это происходит, когда сессия истекает
Во время жизни одной сессии все действия будут проверяться по одному токену.
Если произойдет утечка токена, то злоумышленник сможет выполнить CSRF-Атаку на любой запрос и в течение долгого срока. А это не есть хорошо.
Бесплатная поддержка multi-tab в браузере.
Токен не инвалидируется после выполнения запроса, что позволяет разработчику не заботиться о синхронизации токена в разных табах браузера, так как токен всегда один.
Double Submit Cookie
Этот подход не требует хранения данных на стороне сервера, а значит, является Stateless. Используется, если вы хотите уметь быстро и качественно масштабировать свой Web-сервис горизонтально.
Идея в том, чтобы отдать токен клиенту двумя методами: в куках и в одном из параметров ответа (header или внутри HTML).
При запросе от клиента на стороне сервера генерируется токен. В ответе токен возвращается в cookie (например, X-CSRF-Token ) и в одном из параметров ответа (в header или внутри HTML).
В последующих запросах клиент обязан предоставлять оба полученных ранее токена. Один как cookie, другой либо как header, либо внутри POST данных формы.
Если оба токена совпадают, то запрос не подвергся CSRF-Атаке, в ином случае — логируем событие и отклоняем запрос.
На выходе имеем:
Stateless CSRF защиту.
Таким образом, если ваш сервис доступен на домене 3-го уровня, а злоумышленник имеет возможность зарегистрировать свой ресурс на вашем домене 2-го уровня, то устанавливайте cookie на свой домен явно.
Encrypted Token
Так же как и Double Submit, является Stateless подходом. Основная — если вы зашифруете надежным алгоритмом какие-то данные и передадите их клиенту, то клиент не сможет их подделать, не зная ключа. Этот подход не требует использования cookie. Токен передаётся клиенту только в параметрах ответа.
В данном подходе токеном являются факты, зашифрованные ключом. Минимально необходимые факты — это идентификатор пользователя и timestamp времени генерации токена. Ключ не должен быть известен клиенту.
При запросе от клиента на стороне сервера генерируется токен.
Генерация токена состоит в зашифровке фактов, необходимых для валидации токена в дальнейшем.
Минимально необходимые факты — это идентификатор пользователя и timestamp. В ответе токен возвращается в одном из параметров ответа (В header или внутри HTML).
В последующих запросах клиент обязан предоставлять полученный ранее токен.
Валидация токена заключается в его расшифровке и сравнения фактов, полученных после расшифровки, с реальными. (Проверка timestamp необходима для ограничения времени жизни токена)
Если расшифровать не удалось либо факты не совпадают, считается, что запрос подвергся CSRF-Атаке.
На выходе имеем:
Stateless CSRF защиту
Нет необходимости хранить данные в cookie
О реализации
Давайте генерировать новый токен на каждый запрос, не важно, каким HTTP-методом и с какой целью этот запрос сделан.
Таким образом мы получаем токен, который меняется постоянно.
Конечно, возникает вопрос организации multi-tab работы.
Синхронизация токенов между табами может быть реализована с использованием localStorage и его StorageEvent
Ограничиваем время жизни cookie, которое содержит токен, разумным значением. Например 30 минут.
Делаем cookie недоступной из JS (ставим HTTPOnly=true)
Используем TLS для предотвращения MITM
При этом отправляем cookie только по HTTPS (ставим Secure=true)
Размер токена не менее 32 байт.
Генерируем токен криптографически стойким генератором псевдослучайных чисел.
Для этого можно использовать системные функции:
Что еще нужно знать?
Токены — обязательная защита от CSRF.
Проверяйте, но не полагайтесь только на X-Requested-With: XMLHttpRequest
Не передавайте токены в URL
Same Site
Сейчас идет работа над спецификацией атрибута «Same-Site» у cookies (последняя версия на момент написания статьи).
Такой атрибут даст возможность разработчикам явно указывать, что cookie не нужно передавать, если запрос идет с сайта, отличного от того, на котором cookie была установлена. А, значит, у нас появится возможность защищать ресурсы от CSRF без использования дополнительных инструментов.
Браузер Chrome уже сейчас поддерживает эту возможность.
Чуть больше информации о том, как и почему доступно на Stack Exchange.
JavaScript: Preventing Double Form Submission
A quick double-click on a button or link can have unintended consequences, such as a form being submitted twice, or a script running in parallel to itself and encountering race conditions.
Disabling the Submit Button
In this example, you can click the first button as many times as you want. In practice this can cause a form to be submitted, or some other event triggered, more than once. The second button however will only accept a single click and ignore all subsequent clicks.
The trick is to use JavaScript to set the disabled property of the button to true. The disabled property was first introduced by Microsoft but has since been adopted as a standard by the W3C.
For a simple form, with no associated JavaScripts, you can use:
If you’re already using JavaScript form validation then the command can instead be added to the script as follows:
It’s important that the command to disable the button be added at the end of the script, otherwise, if the validation fails, the user will have no opportunity to re-submit the form.
Using the above code, after the form has been submitted, if the user clicks the browser Back button then the submit button remains disabled. If you don’t want this, read on for some work-arounds.
More User-Friendly
Rather than simply disabling the button, we can also change the text so that people don’t get confused. This example first disables the button and then changes the label from «Submit» to «Please wait. «. The second button restores the initial state:
The code executed when the form is submitted includes the following:
While the HTML for the form itself looks something like:
A triple-click solution
In this slightly more elegant solution the Submit button in this case cycles through three separate states:
In the default state, clicking on the Submit button will call our form validation script (see below) to make sure that all the fields have been populated. If that is not the case then there is an alert message and the script halts.
If/when the form is successfully validated, the button text is changed to «Submitting form. » and a JavaScript variable, submitting is set to true indicating that the form submission is in progress.
A second click on the Submit button before the form has finished submitting will generate an alert message, and also disable the button preventing subsequent clicks. The difference from previous examples is the alert when the button is being disabled.
Our form validation script in this case simply checks that a value has been entered in each of the two form fields. This function is called from an onsubmit event handler attached so it’s called only after any HTML5 form validation requirements have been met.
To test, click the Submit button twice in quick succession. On the second click an alert window will be displayed, while the form continues submitting (from the first click) in the background.
In the HTML for the form the onsubmit handler first checks to see whether the form is already in the process of submitting (second click). If so it displays an alert and disables the submit button to prevent further attempts to submit the form.
If the form is not already being submitted (first click) the handler runs the usual JavaScript validation and, if successful, allows the form to be submitted.
The Reset button and script are just copied from the previous example, with the one addition being that the form_being_submitted variable is also reset back to false.
For an explanation of the required attribute see our article on HTML5 Form Validation.
Using External JavaScript
We’re not changing any of the functionality here, just preparing the JavaScript so it can be moved to an external JavaScript file, and doing away with the necessity for global variables.
First, we strip out any event handlers from the HTML, and assign id values to the elements needing event listeners.
Note that there is no need to assign an id to all the form elements. Only those with event handlers, and even then we could make do with only the FORM having an id if we wanted.
The next step is to define and assign our event handling functions. The main difference here is that each function receives a variable e representing the event, from which e.target can be used to identify which element was targeted.
And in the form validation script instead of return false; we use e.preventDefault(); which prevents the form from submitting, and then return; to exit the script. There is no need for a return true; at the end.
Finally, we wrap all the code in a DOMContentLoaded function allowing us to create variables without them becoming global. This also delays the script initialisation until the HTML is fully loaded.
The JavaScript can now be included either inline on the page, or in a separate JavaScript file referenced by the SCRIPT tag, and it will not interfere with any other scripts on the page because the event listener creates a closure and the contained functions are all defined as local variables.
If you plan to include the JavaScript inline, then instead of using a DOMContentLoaded event handler you can use an IIFE (Immediately Invokable Function Expression) as follows:
(function() < var form_being_submitted = false; var checkForm = function(e) < . >; var resetForm = function(e) < . >; document.getElementById(» test_form «).addEventListener(«submit», checkForm, false); document.getElementById(» reset_button «).addEventListener(«click», resetForm, false); >)();
Preventing double-clicks on links
While the standards suggest that a normal HREF link shouldn’t trigger any action other than navigation, it is often the case that links do trigger an action, and the same problems can arise from people double-clicking.
A quick fix for this is to add an onclick handler to the links that disables it for subsequent clicks:
Working Demonstration
In this scenario the first click on the link will function normally taking the user to the target href. At the same time it adds a new event listener to capture and disable future clicks on the same link.
This example should work in Internet Explorer 9 and higher, and can be made to work in earlier versions with a polyfill for event handling.
References
User Comments
Jaime Hablutzel 24 November, 2016
What is the HTML (or related) standard behavior expected for the browser if the user makes double click on a submit button? I’m seeing that IE11 process a double click as only one click but Google Chrome interprets double click as two submit operations actually.
A click on the submit button submits the form, but depending on your browser and connection speed the window of opportunity for a second click can vary from milliseconds to seconds. Some modern browsers may also have taken measures to prevent duplicate submission.
The reason to use JavaScript is that it disables the submit button instantaneously. A system of single-use client/server tokens can do this as well if you want to avoid relying on JavaScript.
Nicola 26 June, 2014
Hi, I use Fast Secure Contact Form and I like your second solution. BUT, Where I applied? I’m a really noob. Can you explain where I cut/paste your code? I have some field validation, can I disable submit button after all validations are OK?
this doesn’t work in Chrome. fyi.. disabling a submit button stops form submittal
The examples definitely work in Chrome.
Jeremy 24 August, 2013
This is a good solution, HOWEVER, it doesn’t really stand well in 2013. It isn’t really compatible with HTML5’s input «required» attribute. If an input has the required tag, and you press the submit buton, and the field is empty the browser will fire the «Please fill out this field» message, BUT, you also just disabled that submit button. So in effect, the form can no longer be submitted.
This below solution works,
For instance, here is the text input:
The disabled state hangs in FF if you use the backbutton. Try clicking button 2 in the first example, visit another page and navigate back via the backbutton. Button 2 is still disabled.
izwan 14 June, 2012
thanks dude, the third one sure saved me
Dave 23 February, 2008
I am trying to make this work with a page that has JS Code for validation. I placed this at the end of the script. It disabled the button, but the other validation does not work. I know I have missed a step.
I think you need to first read the JavaScript Form Validation article. You seem to have pasted the ‘double submit’ code outside of any function, so it’s being called when the page loads instead of only during form validation.
Две кнопки отправки в одной форме
У меня есть две кнопки отправки в форме. Как определить, какая из них была поражена серверной стороной?
Если вы дадите каждому имя, то выбранное будет отправлено как любой другой ввод.
Решение 1:
присвойте каждому входу различное значение и сохраняйте то же имя:
Затем в коде проверьте, что было сработало:
Проблема в том, что вы связываете свою логику с видимым пользователем текстом на входе.
Еще лучшее решение состоит в использовании тегов кнопок для отправки формы:
Существует новый подход HTML5 к этому, formaction атрибут:
Лично я обычно использую Javascript для удаленной отправки форм (для более быстрой обратной связи) с этим подходом в качестве резервного. Между двумя единственными людьми, которые не охвачены, являются IE тега.
Это очень легко проверить
Просто поместите это на HTML-страницу, нажмите кнопки и посмотрите на URL
Используйте formaction атрибут HTML (5-я строка):
Пример кода сервера (PHP):
elseif очень важно, потому что оба будут проанализированы, если нет. Наслаждаться.
Поскольку вы не указали, какой метод сценариев на стороне сервера вы используете, я приведу пример, который работает для Python, используя CherryPy (хотя это может быть полезно и для других контекстов):
Вместо того, чтобы использовать значение, чтобы определить, какая кнопка была нажата, вы можете использовать имя (с тегом вместо ). Таким образом, если ваши кнопки имеют одинаковый текст, это не вызовет проблем. Имена всех элементов формы, включая кнопки, отправляются как часть URL. В CherryPy каждый из них является аргументом для метода, который выполняет код на стороне сервера. Итак, если ваш метод имеет только **kwargs свой список параметров (вместо утомительного ввода каждого имени каждого элемента формы), вы можете проверить, какая кнопка была нажата следующим образом:
Запретить двойную подачу форм в jQuery
У меня есть форма, которая требует немного времени для обработки сервера. Я должен убедиться, что пользователь ждет и не пытается повторно отправить форму, нажав кнопку еще раз. Я попытался использовать следующий код JQuery:
Когда я пытаюсь сделать это в Firefox, все отключается, но форма не отправляется ни с какими данными POST, которые она должна включать. Я не могу использовать jQuery для отправки формы, потому что мне нужно, чтобы кнопка была отправлена вместе с формой, поскольку есть несколько кнопок отправки, и я определяю, какое из них использовалось, какое значение включено в POST. Мне нужно отправить форму как обычно, и мне нужно отключить все сразу после того, как это произойдет.
Обновление в 2018 году : я только что получил несколько баллов за этот старый ответ и просто хотел добавить, что лучшим решением было бы сделать операцию идемпотентной, чтобы дублирующие представления были безвредными.
Например, если форма создает заказ, поместите уникальный идентификатор в форму. Когда сервер впервые видит запрос на создание заказа с таким идентификатором, он должен создать его и ответить «успех». Последующие представления также должны отвечать «успех» (в случае, если клиент не получил первый ответ), но не должны ничего менять.
Дубликаты должны быть обнаружены с помощью проверки уникальности в базе данных, чтобы предотвратить состояние гонки.
Я думаю, что ваша проблема заключается в этой строке:
Вы отключаете ВСЕ входные данные, в том числе, я полагаю, те, чьи данные должна предоставить форма.
Чтобы отключить только кнопку отправки, вы можете сделать это:
Тем не менее, я не думаю, что IE отправит форму, если даже эти кнопки отключены. Я бы предложил другой подход.
Плагин JQuery, чтобы решить это
Мы только что решили эту проблему с помощью следующего кода. Хитрость здесь в том, чтобы с помощью jQuery data() пометить форму как уже отправленную или нет. Таким образом, нам не нужно связываться с кнопками отправки, что выводит IE из себя.
Используйте это так:
Если есть формы AJAX, которые нужно разрешить отправлять несколько раз за загрузку страницы, вы можете дать им класс, указывающий на это, а затем исключить их из вашего селектора следующим образом: