Как определить корректность запроса пользователя
Представим, что мы разрабатываем социальную сеть, и нам нужно реализовать функцию публикации поста. Если не проверять данные, которые вводит пользователь, то мы можем получить пост с пустым или слишком длинным текстом. Обычно такие ошибки приводят к некорректному поведению в приложениях. Это не хорошо, потому что пользователь не сможет понять, что произошло, и нам придется разбираться, почему пост не опубликовался.
В этом уроке мы разберем, как проверять HTTP-запросы в Go. Это важно, потому что проверки позволяют избежать ошибок и обеспечить безопасность нашего приложения.
Ручная проверка запросов в Go
Процесс проверки запросов на корректность перед последующей обработкой называется валидацией:
У разработчиков есть несколько вариантов реализации валидации в Go. В некоторых проектах придерживаются идеологии простоты чтения кода и реализуют валидацию вручную.
Например, валидация запроса на сохранение поста может выглядеть следующим образом:
Запускаем веб-приложение и отправляем запрос на создание поста с некорректными данными:
В данном запросе мы указали некорректный идентификатор пользователя и пустой текст поста. В ответ получаем сообщение об ошибке:
Попробуем отправить корректные значения:
В ответ приходит статус 200 OK, что означает успешное прохождение проверок.
Таким образом, мы настроили проверку запросов, которые приходят в наше веб-приложение. Если запрос на создание поста содержит некорректные данные, то мы возвращаем ошибку. В случае успешной валидации запроса мы возвращаем ответ со статусом 200 OK.
Со стороны кода в данной реализации все проверки описаны явно и легко читаются. Когда новый разработчик присоединится к проекту, он быстро поймет логику приложения, и как проверяются запросы.
У этого подхода также есть один значимый недочет: этот подход плохо масштабируется. Если у нас будет много различных методов с множеством полей, которые нужно проверить, то код станет громоздким. В итоге со временем может возникнуть много повторяющегося кода.
Второй недочет — мы выводим по одной ошибке в одном ответе. Например, структура запроса состоит из пяти полей. Все поля заполнены неверно. В текущей реализации пользователю придется сделать пять запросов, при этом исправлять по одному полю после каждого ответа. Это неудобно, поэтому мы бы хотели возвращать все ошибки в одном ответе.
Чтобы решить эти недочеты, следует использовать готовую библиотеку для валидации запросов. Мы рассмотрим самую часто используемую библиотеку в Go — go-playground/validator. Далее будем ее называть Validator.
Валидация запросов с помощью Validator
Библиотека Validator позволяет реализовать валидацию запросов с помощью аннотаций полей структур. Для каждого поля структуры мы описываем список правил проверок, которые необходимо осуществить. Например, валидация запроса на публикацию поста может выглядеть следующим образом:
Запускаем веб-приложение и отправляем запрос на создание поста с некорректными данными:
В данном запросе мы указали некорректный идентификатор пользователя и пустой текст поста. В ответ получаем сообщение об ошибке:
Попробуем отправить корректные значения:
В ответ приходит статус 200 OK, что означает успешное прохождение проверок.
Так мы реализовали валидацию запросов с помощью библиотеки Validator. Когда мы передаем некорректные данные, то в ответ получаем сообщение об ошибке. Оно позволяет понять, какие данные необходимо исправить. Если все данные заполнены правильно, то мы получаем статус 200 OK.
Мы видим, что в данном случае код стал намного короче и легче читается. Мы можем описывать новые правила валидации и не добавлять новых функций и логики.
Однозначное преимущество по сравнению с ручной валидацией — библиотека уже содержит в себе множество готовых правил проверок, которые можно использовать в своих проектах. Например, мы можем проверить, что поле является корректной электронной почтой:
Полный список правил проверок можно смотреть в документации.
Пользовательские валидаторы
Готовые правила обычно покрывают большинство нужд в валидации запросов. Но иногда нужно добавить свои правила с пользовательской логикой. Для этого можно использовать функцию validate.RegisterValidation() .
Например, мы хотим проверить, что в публикуемом посте отсутствуют слова-фильтры. Для этого мы напишем следующий код:
Запускаем веб-приложение и отправляем запрос на создание поста с текстом, который содержит слово-фильтр:
В ответ получаем валидационную ошибку:
Если же отправить запрос с текстом без запрещенных слов, то получим успешный ответ:
В итоге мы описали пользовательское правило валидации по тегу allowable_text. Оно проверяет, что текстовое поле не содержит запрещенных слов.
Когда приходит запрос с запрещенным словом, валидация не проходит, а клиенту возвращается ошибка. Если в запросе передать корректный текст, то валидация пройдет успешно, и клиент получит ответ со статусом 200 OK.
Выводы
- В веб-приложениях следует проверять все запросы на корректность, чтобы избежать ошибок и уязвимостей
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
О том, как можно проверять значения, введёные пользователем
В любых программных продуктах, будь то windows-приложение или web-сайт, получение информации от пользователей зачастую осуществляется с помощью форм ввода данных.
Конечно же, нельзя быть абсолютно уверенным, что пользователь введёт именно то, что нужно, поэтому все данные необходимо тщательно проверить.
Как правило, алгоритм проверки этих данных один и тот же: «Если значение поля удовлетворяет требованию, то проверить следующее требование, иначе вывести сообщение об ошибке. Перейти к проверке значения следующего поля».
На практике это выливается с довольно длинные последовательности «if-else». Лично мне это жутко не нравилось, так как сложно с первого взгляда определить, какие поля как проверяются и какие сообщения выдаются в случае ошибок. А ведь полей в форме может быть и десять, тогда код проверки вообще затягивается. Вобщем, я задумался над тем, как можно минимизировать объём работ и вот что из этого получилось.
Я представил проверку как преобразование значения одного типа в значение другого типа (например, проверка того, что в поле введено чило, это преобразование строки в число). Тоесть проверка — это некая функция, имеющая сигнатуру делегата System.Converter<T, U>.
Для проверки значение помещаем в класс обёртку:
Суть проверки заключается в последовательном вызове методов-расширений для объектов класса ValidationStep<T>, которые опять же возращают объект класса ValidationStep<T>. Это позволяет создавать цепочки проверок. Вот пример таких методов-расширений:
Первый метод используется, чтобы можно было проверять объекты любых типов, торой метод осуществляет проверку на соответствие предикату, а третий на возможность преобразования значения из одного типа в другой. Также можно написать любые другие проверки, например на соответствие целого числа диапазону. Главное, что в случае неудачной проверки должно возникать исключение ValidationException, которое содержит сообщение с текстом ошибки.
Для осуществления самой проверки можно использовать следующий класс, который будет заниматься перехватом исключений:
А теперь о том, как это использовать. Допустим нам нужно проверить текстовое поле (tb1) и убедиться, что в него введено целое число в диапазоне от 0 до 10. Это можно сделать так:
Учитывая, что проверок может быть больше, да и число полей в форме, как правило, больше одного, такой способ проверок может быть очень даже удобен.
Проверка корректности данных
Проверке корректности данных, вводимых пользователем необходимо уделять достаточно большое внимание, поскольку необработанные ошибки, возникающие при вводе неправильном вводе данных, приводят к ошибкам в работе скрипта, зачастую катастрофическим. Предположим, вы создаете форму для отправки пользователем письма, при этом адрес электронной почты необходимо вводить пользователю. В этом случае, для корректной работы программы вы должны сделать, по крайней мере, две вещи:
- Проверить, что поле, в которое заносится электронный адрес непустое (поскольку пользователь может просто забыть ввести адрес, и, если этот случай необработан, возникнет ошибочная ситуация);
- Проверить соответствие введенного адреса с помощью регулярного выражения.
Кроме чистых ошибок пользователя, необходимо также исключить ситуации, в которых возможно злонамеренное введение некорректных данных, к примеру, различных скриптов. Для этого вводимый пользователем текст необходимо обработать функциями удаления HTML-тегов (для исключения возможности написания скриптов на JavaScript и Visual Basic) и обратных слешей (для исключения возможности написания скриптов на Perl). Т. о. минимальный набор действий, необходимый для проверки корректности данных, вводимых пользователем, включает следующие этапы:
- проверка того, что пользователь ввел данные
- проверка допустимости вводимых пользователем данных (как правило, осуществляется при помощи регулярных выражений)
- обработка текста, введенного пользователем функцией htmlspecialchars для удаления HTML-тегов
- обработка текста, введенного пользователем функцией stripslashes для удаления обратных слешей
Проверка на пустоту поля
Проверка того, что пользователь ввел данные, может осуществляться, к примеру, с помощью функции isset:
Для этой же цели можно использовать функцию empty:
На практике удобно сначала проверить, не пустой ли action формы, а потом уже проверять различные его составляющие: поле имя, e-mail и т. д. К примеру:
Проверка допустимости вводимых данных
Пусть нам надо проверить данные формы для отправки сообщения гостевой книги. Как правило, такая проверка осуществляется при помощи регулярных выражений. Рассмотрим пример, в котором создается регулярное выражение для проверки адреса электронной почты.
Будем исходить из того, что адрес должен иметь вид something@server.com. Как видим, у адреса две составляющие — имя пользователя и имя домена, которые разделены знаком @. В имени пользователя могут присутствовать буквы нижнего и верхнего регистров, цифры, знаки подчеркивания и минуса, точки. Для проверки разделителя между именем пользователя и именем домена в выражение требуется добавить +@. Таким образом, регулярное выражение, проверяющее имя пользователя и наличие разделителя имеет следующий вид:
Для проверки доменного имени добавляем такое выражение:
Объединяя эти шаги, получаем следующее регулярное выражение для проверки адресов электронной почты:
Точно таким же образом вы можете проверить и остальные заполняемые пользователем поля.
Удаление HTML — тегов и обратных слешей
Как уже говорилось, вводимый пользователем текст необходимо обработать функциями удаления HTML-тегов (для исключения возможности написания скриптов на JavaScript и Visual Basic) и обратных слешей (для исключения возможности написания скриптов на Perl). К примеру, если переменная $name содержит текст с именем пользователя, то обработка этого текста выглядит так:
Если Вам нужна частная профессиональная консультация от авторов многих книг Кузнецова М.В. и Симдянова И.В., добро пожаловать в наш Консультационный Центр SoftTime.
4 шага проверки входных данных приложением?
Любое приложение, которое взаимодействует с внешним миром посредством каких либо интерфейсов, сталкивается с задачей фильтрации и проверки вводимой информации.
Количество разработчиков и производимых ими продуктов растёт, а их квалификация и качество падает. Моё мнение: это связано с отсутствием инженерных навыков у современных разработчиков, так как современный мир убеждает, что достаточно закончить курсы, а образование, умение структурированно мыслить и учиться новому это удел отраслевых пенсионеров.
Чтобы закрыть эту зияющую дыру, я решил написать этот небольшой ликбез.
Ниже будет описана последовательность действий для проверки входных данных, которые я сформировал исходя из личного опыта. Я не исключаю, что его можно дополнить или улучшить, либо реализовать иначе, но фундаментально вряд ли что-то изменится.
1. Проверка на наличие
Любые входные данные могу содержать как обязательные значения/поля, так и необязательные.
Эта проверка касается исключительно обязательных величин.
Приложению ресурсно выгодно отсечь неправильные входные данные, не углубляясь в ресурсозатратные проверки.
Что нужно сделать:
- проверить наличие всех обязательных значений/полей;
- если хотя бы одного значения/поля нет, то необходимо прекратить дальнейшую проверку и вернуть ответ с ошибкой.
На что приложение потратит ресурсы на этом этапе:
- на парсинг входных данных, если это необходимо;
- на проверку наличия обязательных значений/полей.
Такими минимальными затратами приложение может уже отсечь часть некорректных входных данных. В случае веб-приложения, этот высвободившийся ресурс может пригодиться во времена DOS атаки на ресурс.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных
Пример корректных данных
Всего лишь одной проверкой наличия required можно отсечь этот запрос без детальной проверки всех значений/полей.
2. Проверка на тип данных
Второй этап такой же простой как и предыдущий, и может дать не меньшую экономию ресурсов.
Входные данные состоят из значений/полей разных типов данных (речь про примитивные типы данных). Комплексные типы состоят из примитивных, следовательно, их точно так же можно проверить.
Что нужно сделать:
- проверить каждое значение/поле по его типу (string/int/uint/float/boolean);
- если хотя бы одно значение/поле имеет неожидаемый тип данных, то необходимо прекратить дальнейшую проверку и вернуть ответ с ошибкой.
Порядок проверки по типу данных следует выполнять в следующем порядке:
- обязательные значения/поля;
- наиболее часто встречаемые значения/поля при их наличии;
- все остальные при их наличии.
Пример:
Ожидаемая JSON структура аналогична как у предыдущего примера.
Пример некорректных данных
Этот этап на столько же эффективен как и предыдущий, но чутка более ресурсоёмкий.
3. Проверка на формат
Данный этап при надлежащем применении может отсечь большую часть кодовых инъекций.
Под эту проверку попадают все значения/поля, кроме типа boolean. Они уже досконально проверены на предыдущих этапах.
В чём суть:
Мы заранее знаем, что мы получим от потребителя приложения. Толи это будут какие-то числа, толи текст, или массив каких-то типов.
- если получаем int/uint/float значение и оно должно быть в рамках каких-то диапазонов или ограничений, нужно убедиться, что оно действительно так.
- если получаем string и это не свободный текст, то нужно его проверить по формату.
Способы проверки значений типа string:
- разделение на смысловые блоки и простыми логическими операциями проверяем значение (менее ресурсоёмко, но дольше в реализации);
- используем регулярные выражения (более ресурсоёмко, но быстрее в реализации в умелых руках).
Порядок проверки по типу данных следует выполнять как и на предыдущем этапе в следующей последовательности:
- обязательные значения/поля;
- наиболее часто встречаемые значения/поля при их наличии;
- все остальные при их наличии.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных
Как проверяем:
- так как поле some_field содержит свободный текст, его содержимое следует экранировать самостоятельно средствами языка для использования внутри приложения, либо средства драйверов СУБД для хранения и обработки в базе данных;
- поле kidneys должно быть в диапазоне [0, 2] (вспоминаем школьную математику и биологию, которая нафиг были не нужны ); следовательно, так как переданное значение не попадает в заданный диапазон, следует прекратить обработку и вернуть ошибку;
- поле email можно проверить двумя способами: простыми операциями и проверками или при помощи регулярных выражений. Ниже опишу оба способа проверки. По аналогии, если поле не проходит проверку, нужно вернуть обработку и вернуть ошибку.
Способы проверки поля email простыми операциями:
- убедиться, что значение содержит символ @ ;
- убедиться, что символ @ не первый и не последний;
- проверить длину email`а, она не должна превышать 320 символов ( @ ).
Для минимальной проверки email`а этих действия чаще всего достаточно.
Способы проверки поля email регулярным выражением:
Используя регулярное выражение ниже нужно выполнить в проверку значения
4. Логическая проверка
Этот этап, судя из регулярный новостей о поломках различных государственных/крупных коммерческих сайтов чужд разработчикам их создавшие.
Эта проверка наиболее ресурсоёмкая и вот почему: если в запросе фигурирует поле с идентификатором чего либо, нужно убедиться, что запись с данным идентификатором уже есть в информационной системе, за исключением тех запросов, которые должны эту запись создать.
- допустим, все данные хранятся в единой базе данных;
- для проверки идентификатора понадобится сделать запрос к базе данных, что требует ресурсов приложения на удержание запроса, на подключение к базе данных и на обработку запроса самой базой данных, и самое главное, может увеличить время исполнения в разы;
Как можно упростить решение и сделать его менее ресурсоёмким:
- использовать In-Memory хранение нужных идентификаторов в приложении;
- использовать быстрые кеш-машины для хранения нужных данных;
- использовать поисковые движки, которые будут в реальном времени индексировать нужные данные; использую поисковые индексы можно быстро проверять нужные индексы;
- организовывать запросы так, чтобы ресурсоёмкость запросов свести к минимуму.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных:
Пример потенциально корректных данных:
Но нам нужно убедиться, что пользователь с ID 1 существует и не заблокирован.
Как проверяем (простой пример с СУБД):
Допустим у нас есть некая таблица в базе данных со следующей структурой:
- нужно подключиться к базе данных;
- проверить, есть ли такой пользователь;
- у этого пользователя флаг is_available равен ли true ;
- у этого пользователя флаг is_removed равен ли true ;
- всё это несложно организовать одним запросом.
Эта простая проверка позволяет не допустить получение доступа к чужой пользовательской информации или выйти за пределы задуманной функциональности приложения.
Выводы
Из своего опыта могу сказать, что подобным списком проверок пользуются небольшое количество знакомых разработчиков, а знаю я достаточно много. Чаще всего разработчики полагаются на некий мифические фреймворки, которые за них проверят и обезопасят приложение. Могу сказать лишь одно: если бы в жизни ИТ всё было так просто, то какого чёрта специалисты имеют заработки выше рынка?
1.5. Проверка данных, вводимых
Как правило, через интерфейс пользователи передают приложениям различную информацию. Проверка вводимых данных гарантирует, что пользователю разрешается продолжить работу с программой только после ввода данных, отвечающих заданным параметрам. Предположим, что в группе полей для ввода адреса есть поле почтового индекса. Прежде чем принять введенное в это поле значение, следует удостовериться, что пользователь ввел именно пять символов, причем все пять — цифры. Проверка введенных пользователем данных уменьшает вероятность ошибки ввода и повышает устойчивость приложения.
На этом занятии вы научитесь применять события для проверки пользовательского ввода и передачи фокуса ввода другим формам и узнаете, как выполнить проверку на уровне полей (когда поля проверяются по мере их заполнения) или на уровне формы (когда все поля проверяются одновременно). Вы также научитесь задавать диапазон допустимых значений при помощи свойств элемента управления и применять компонент ErrorProvider для отображения пользователю сообщений с описанием допущенной им ошибки.
Разработчик вправе указать один из двух типов проверки вводимой информации: на уровне поля и на уровне формы. Проверка на уровне формы выполняется после того, как пользователь заполнит все поля формы. Предположим, что пользователь должен заполнить поля для ввода имени, адреса и номера телефона, а затем щелкнуть ОК. Если задана проверка на уровне формы, все поля формы проверяются одновременно после щелчка кнопки ОК.
При использовании проверки на уровне поля все поля проверяются по отдельности по мере их заполнения. Например, прежде чем пользователь перейдет к следующему полю после ввода телефонного номера, в указанном им номере проверяется код города. Применение событий элементов управления позволяет по мере ввода символов номера удостовериться, что вводимые символы являются цифрами.
Проверка на уровне поля
В ряде случаев необходимо проверять данные сразу же после их ввода, что позволяет осуществлять проверку полей по мере их заполнения
Применение свойств элемента управления TextBox
Чаще всего для приема данных от пользователя применяется элемент управления TextBox. Некоторые из его свойств позволяют ограничивать диапазон значений, вводимых в текстовое поле, например:
• PasswordChar
Свойство MaxLength ограничивает число символов, которые можно ввести в текстовое поле. Если пользователь попытается ввести больше символов, чем задано свойством MaxLength, текстовое поле не примет избыточные символы, а пользователь услышит звуковой сигнал. С помощью этого свойства удобно создавать поля для ввода значений фиксированной длины, например почтовых индексов.
PasswordChar
Свойство PasswordChar позволяет скрывать от посторонних глаз значение, вводимое во время выполнения. Например, если сделать значением свойства PasswordChar звездочку (*), текстовое поле будет отображать все вводимые пользователем символы как звездочки. Этот прием обычно используют для защиты паролей в окнах входа.
Для замены пароля вы можете назначить любой допустимый символ, например точку с запятой или знак «&». Независимо от назначенного символа, свойство Text всегда содержит то значение, которое реально ввел пользователь.
Свойство ReadOnly определяет, разрешено ли пользователю редактировать значение текстового поля. Если это свойство установлено в true, пользователю не удастся изменить отображаемый в поле текст, в противном случае значение текстового поля можно редактировать, как обычно.
Свойство Multiline определяет, одна или много строк в поле. Если оно установлено в true, пользователь может вводить многострочный текст, завершая строки символом возврата каретки. Введенные строки сохраняются в виде строкового массива в наборе Text Box. Lines. Чтобы получить нужную строку, следует указать ее индекс в массиве.
Применение событий для проверки на уровне поля
Обработка событий, связанных с клавиатурой, на уровне поля позволяет немедленно проверять любые данные, вводимые пользователем. Элементы управления, способные принимать ввод с клавиатуры, генерируют следующие три события:
События KeyDown и KeyUp
Нажатие и освобождение любой клавиши сопровождается генерацией события KeyDown и KeyUp соответственно. Источником событий является элемент управления, обладающий фокусом ввода. Элемент управления, генерировавший событие, передает сведения о нажатой (или отпущенной) клавише (или сочетании клавиш) через экземпляр класса KeyEventArgs — класса, описывающего сочетание клавиш. В сигнатуре метода, обрабатывающего событие KeyDown или KeyUp, должен быть параметр типа KeyEventArgs.
Чаще всего события KeyDown и KeyUp используют, чтобы определить, нажаты ли клавиши Alt, Ctrl или Shift. Результат передается обработчику соответствующего события через ссылку на экземпляр класса KeyEventArgs. Его свойства Ait, Ctrl и Shift возвращают значения типа Boolean, указывающие, были ли нажаты соответствующие клавиши. Значение True свидетельствует о том, что клавиша была нажата, а false — о том, что нет. Ниже показан пример обработчика события KeyUp, проверяющего нажатие клавиши Alt:
private void textBox1_KeyUp(object sender,
MessageBox.Show(«The ALT key is still down»);
Свойство KeyEventArgs.KeyCode позволяет определить, какая именно клавиша спровоцировала событие. Это свойство возвращает код нажатой или отпущенной клавиши (соответственно при событиях KeyDown или KeyUp). Ниже показан пример простого обработчика события, отображающего сообщение с кодом нажатой клавиши:
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
Когда пользователь нажимает клавишу, которой соответствует значение ASCII, генерируется событие KeyPress. К этим клавишам относятся все алфавитно-цифровые клавиши (a— z, A— Z, 0—9), а также ряд специальных клавиш, таких, как Enter и Backspace. Если при нажатии клавиши или их комбинации не генерируется ASCII-символ, событие KeyPress также не генерируется. К таким клавишам относятся клавиши -модификаторы Ctrl и Alt, а также все функциональные клавиши.
Это событие очень удобно для перехвата нажатия клавиш и проверки соответствующих символов. При генерации события KeyPress обработчик получает экземпляр класса KeyEventArgs, свойство Key EventArgs. Key Code которого содержит ASCII-символ клавиши, нажатие которой спровоцировало это событие. Чтобы проверить, например, была ли нажата цифра, достаточно проверить свойство KeyChar в обработчике события KeyPress.
Проверка вводимых символов
Тип данных Char поддерживает несколько статических [Shared (static)] методов, удобных для проверки символов, переданных событием KeyPress:
• Char.IsDigit
• Char.IsLetter
• Char. IsLetterOrDigit
• Char. Is Punctuation
• Char.IsLower
• Char.IsUpper
Все они проверяют символы и возвращают булевы значения. Что проверяет каждый метод — легко догадаться по его имени. Функция Char.IsDigit возвращает true, если переданный ей символ является цифрой, и false в любом другом случае; Char.IsLower возвращает true, если ее аргументом является буква в нижнем регистре, и false в противном случае; сходным образом работают остальные методы. Вот пример применения метода Char.IsDigit для проверки нажатия цифр на клавиатуре:
private void textBox1_KeyPress (object sender,
System. Windows. Forms. KeyPressEventArgs e)
if (Char. IsDigit(e. KeyChar) == true)
MessageBox.Show(«You pressed a number key»);
Работа с фокусом ввода
Объект, обладающий фокусом, способен получать пользовательский ввод, осуществляемый мышью или через клавиатуру. На форме может быть несколько элементов управления, но в каждый момент времени фокус ввода только у одного из них.
Элемент управления, обладающий фокусом, всегда находится на активной форме приложения.
У каждого элемента управления есть метод Focus, который передает фокус ввода вызвавшему его элементу управления. Метод Focus возвращает булево значение, свидетельствующее об успешной или неудачной передаче фокуса. Деактивированные или невидимые элементы управления не получают фокус ввода. Определить, способен ли данный элемент управления получить фокус ввода, позволяет его свойство CanFocus: если оно возвращает true, элемент управления может получить фокус, а если false — нет.
// Проверить, может ли TextBox1 получить фокус,
// и, если да, передать ему фокус.
if (textBox1.CanFocus == true)
События, связанные с передачей фокуса, генерируются в следующем порядке:
4. Validating
5. Validated
6. LostFocus
События Enter, Leave генерируются, когда фокус переходит к элементу управления (но еще не получен им) и покидает его. События GotFocus и LostFocus генерируются при получении и потере фокуса элементом управления. В принципе, эти события можно применять для проверки вводимых значений на уровне поля, однако события Validating и Validated лучше подходят для этой цели.
События Validating и Validated
Проще всего проверить вводимые данные при помощи события Validating, генерируемого перед потерей фокуса элементом управления. Это событие генерируется, только если у элемента управления, который получит фокус следующим, свойство Causes Validation установлено в true. Поэтому, если значение элемента управления предполагается проверять при помощи события Validating, для элемента управления, который получит фокус следующим, свойство CausesValidation следует установить в true. Кроме того, использование события Validating требует, чтобы свойство CausesValidation у проверяемого элемента управления было установлено в true. У всех элементов управления, созданных во время разработки, свойство CausesValidation установлено в true по умолчанию, обычно исключение составляет лишь кнопка Help.
Событие Validating позволяет выполнять довольно сложную проверку значений элементов управления. Обработчик этого события способен, например, проверять соответствие введенного значения некоторому весьма специфическому формату или запрещать передачу фокуса другому элементу управления, пока пользователь не введет какое-либо значение.
Событие Validating включает экземпляр CancelEventArgs — класса с единственным свойством Cancel. Если введенное значение не отвечает заданным параметрам, проверив свойство Cancel в обработчике события Validating, можно отменить дальнейшую обработку этого события и вернуть фокус исходному элементу управления.
Событие Validated генерируется после успешной проверки значения элемента управления и позволяет выполнить некоторые действия в зависимости от результатов проверки.
Ниже показан пример обработчика события Validating, который не разрешает передать фокус следующему элементу управления, пока пользователь не введет значение в поле TextBoxl.
private void textBox1_Validating(object sender,
System. ComponentModel. CancelEventArgs e)
// Проверить значение TextBoxl
Применение события Validating для проверки текстового поля
1. Поместите на форму текстовое поле.
2. Создайте для него обработчик события Validating, устанавливающий свойство e. Cancel в true, чтобы прервать проверку и вернуть фокус текстовому полю.
3. Для всех элементов управления, которые не должны генерировать событие Validating, установите свойство Causes Validation в false.
Проверка на уровне формы
Проверка на уровне формы позволяет одновременно проверить все поля формы.
Для подобной проверки обычно применяют процедуру, которая вызывается, когда пользователь готов открыть другую форму; более совершенный способ — обработка на уровне формы события, связанного с клавиатурой.
Ниже показан пример метода, выполняющего проверку на уровне формы. По щелчку кнопки btnValidate этот метод проверяет, все ли текстовые поля формы заполнены. Если обнаружено пустое поле, метод передает ему фокус.
private void btnValidate_Click(object sender, System. EventArgs e)
// Проверить все элементы управления формы в цикле.
foreach (System. Windows. Forms. Control aControl in this. Controls)
// Если этот элемент управления — текстовое поле,
// проверить, не пусто ли оно.
if (aControl is System. Windows. Forms. TextBox && aControl. Text ==””
// передать ему фокус и выйти из метода.
Обработка событий клавиатуры на уровне формы
Обработка связанных с клавиатурой событий на уровне формы — более сложная методика, чем показанная только что. Централизованная обработка событий, связанных с клавиатурой, позволяет управлять вводом данных в любое поле формы.
Например, можно написать метод, активирующий командные кнопки только после заполнения всех полей формы и выполняющий определенные действия в зависимости от того, какие клавиши нажимаются.
Обработку событий на уровне формы реализуют с применением событий KeyPress , KeyDown и KeyUp. Форма автоматически генерирует события клавиатуры, только если на ней нет активированных или видимых элементов управления, в противном случае эти события генерирует элемент управления, получающий фокус.
Чтобы заставить форму автоматически генерировать события клавиатуры, следует установить ее свойство KeyPreview в true — в результате форма будет генерировать эти события прежде элемента управления, получившего фокус. Предположим, что событие KeyPress обрабатывается и формой, и размещенным на нем текстовым полем, а свойство KeyPreview формы установлено в true. При нажатии клавиши форма первой генерирует событие KeyPress, поэтому ее обработчик этого события исполняется первым, и только после его завершения будет исполнен обработчик события KeyPress текстового поля.
Оповещение пользователя об ошибках ввода
Если пользователь ввел в поле недопустимое значение, необходимо оповестить его об этом и дать возможность исправить ошибку. Существует много способов уведомления об ошибках ввода. Если ошибка очевидна и ее не требуется пояснять, можно ограничиться звуковым сигналом.
Примечание В Visual C# нет встроенных методов, отвечающих за подачу звуковых сигналов.
Привлечь внимание пользователя к ошибке можно и по-другому, изменив цвет фона или текста элемента управления (при помощи его свойств BackColor и ForeColor соответственно). Например, выделить текстовое поле с недопустимым значением, задав для него красный фон через свойство BackColor.
Чтобы вывести более информативное описание ошибки, воспользуйтесь методом MessageBox.Show, отображающим небольшое модальное окно с сообщением.
Поскольку это окно — модальное, пользователю не удастся просто игнорировать его и продолжить работу с программой. Вот пример вызова метода Message Box. Show;
MessageBox.Show(«That value is not valid for this control»);
Компонент ErrorProvider
Компонент ErrorProvider предоставляет удобный способ оповещения пользователей о допущенных ими ошибках ввода. Он позволяет задать для каждого элемента управления формы текст сообщения, отображаемого при вводе недопустимого значения. Если для элемента управления задан текст сообщения об ошибке, то при возникновении ошибки рядом с ним появится соответствующий значок, а если навести на него указатель мыши, отобразится всплывающая подсказка с заданным сообщением. Компонент ErrorProvider расположен в секции Windows Forms панели Toolbox.
Отображение сообщений об ошибках
Метод SetError компонента ErrorProvider позволяет вывести сообщение об ошибке рядом с элементом управления. Этот метод принимает имя элемента управления и текст сообщения об ошибке в качестве параметров; вызывают его так:
// Предполагается существование элемента управления nameTextBox
// и компонента ErrorProvider с именем myErrorProvider.
myErrorProvider.SetError(nameTextBox, «Name cannot be left blank!»);
В результате исполнения этого кода поле nameTextBox отображает значок, а при наведении на этот элемент управления указателя мыши появляется всплывающая подсказка с заданным текстом.
Сообщение об ошибке разрешается задавать и во время проектирования Если изучить окно Properties после добавления на форму компонента ErrorProvider, нетрудно заметить, что у каждого элемента управления появилось новое свойство Error on х, где х — имя экземпляра ErrorProvider. Во время проектирования значение этого свойства задают через окно Properties, во время выполнения заданное таким образом значение отображается как сообщение об ошибке для данного элемента, Ряд свойств компонента ErrorProvider определяет способ отображения сообщения об ошибке. Свойство Icon задает значок, отображаемый после элемента управления. Одна форма может содержать несколько экземпляров ErrorProvider, например один, отображающий сообщения об ошибках, а другой — предупреждения, при этом каждому экземпляру ErrorProvider разрешается назначить собственный значок. Другое свойство этого компонента — BlinkStyle — заставляет значок мигать, частоту мигания определяет свойство BlinkRate.
Применение компонента ErrorProvider при создании обработчика события, проверяющего значение элемента управления
1. Создайте форму и добавьте к ней компонент ErrorProvider — он появится в области компонентов.
2. Установите в true свойство CausesValidation элемента управления, который должен выводить сообщения об ошибках, если это еще не сделано.
3. Добавьте к обработчику события Validating этого элемента управления код, проверяющий введенное в него значение. При помощи метода SetError установите текст сообщения, которое отображается, если при проверке введенного обнаружится ошибка. Вот пример обработчика, использующего экземпляр компонента ErrorProvider с именем my Error Provider; этот обработчик проверяет текстовое поле pswordTextBox:
private void pswordTextBox_Validating(object sender,
// Проверить введенное значение,
myErrorProvider. Set Error (pswordTextBox, «Password cannot be blank!»);
// Если введено допустимое значение, очистить текст сообщения:
// поскольку ошибки нет, сообщение не выводится.
Преобразование типов
Для преобразования типов используются следующие методы:
// преобразование текста в целое число int balance = Convert.ToInt32(textBox1.Text); // преобразование целого числа в текст textBox1.Text = Convert.ToString(balance);
Процесс создания приложения заключается в выполнении следующих шагов:
1. Создать интерфейс приложения (перетащить все необходимые компоненты, настроить их свойства).
Проводим тестирование и анализ поиска в интернет магазине. На примере
В интернет-магазинах день за днем происходят сотни тысяч визитов, и каждый из них может стать потенциальной покупкой для компании. Анализ поведения пользователей на сайте является ключевым моментом в развитии любого интернет-магазина, позволяя определить причины, по которым пользователи покидают сайт, и выработать соответствующие решения.
В данной статье мы рассмотрим результаты анализа поведения пользователей на сайте Кабель РФ [ссылка удалена модератором] , на примере данных, полученных из Яндекс.Метрики, Google аналитики и UI тестирования. Данные были собраны методом веб-аналитики и представляют собой набор показателей, таких как количество визитов, отказов, длительность сессии и др.
Возможно кому-то будет полезен некий алгоритм анализа и тестирования работы поиска на конкретном примере.
В ходе анализа было выявлено, что основные причины покидания сайта пользователем связаны с необходимостью находить нужную информацию и поиском продукта. Согласно данным, около 25% пользователей покидают сайт из-за того, что не могут найти необходимый товар. А это, в свою очередь, ведет к снижению конверсии и снижению прибыли интернет-магазина.
Ну а теперь отправляемся смотреть как работает наш поиск)
1) Сначала мы рассмотрим вопрос поиска на сайте. Важным моментом является правильная работа поиска, который должен отображать результаты, соответствующие запросу пользователя. Однако наш анализ показал, что поиск по совпадениям в названии товара не всегда отрабатывает корректно и предлагает много продуктов, не соответствующих запросу пользователя. Это значительно затрудняет поиск продукта и, как правило, приводит к покиданию сайта. Поэтому важно уделить внимание оптимизации работы поиска.
Почему это так плохо? Пользователь смотрит в поисковую выдачу и видит много товаров, которые не совпадают с его запросом. Он начинает думать что такого товара нет в магазине и не важно что искомый товар был на второй странице поиска, туда мало кто ходит)
Пример: Пользователь вбивает запрос “люминесцентная лампа е27”, а в поисковой выдаче “Лампа галогенная”, “Лампа светодиодная” и т.д.

2) Так же было замечено, что при вводе спецсимволов поиск работает некорректно. Конкретнее на примере. При вводе поискового запроса с сечением и напряжением кабеля мы вбиваем в запрос дробное число с точками “КГт 3×0.75 ” в выдаче открывается листинг(список) с большим кол-вом результатов, среди которых товары с разными параметрами.

Если заменить точку на запятую “КГт 3×0,75”, то по запросу открывается карточка конкретного товара. Почему это важно? Пользователи часто ищут конкретный кабель с известными им параметрами и многие дробные числа вводят с точками. А учитывая, что встречаются случаи, при которых из-за точек, искомый товар в поисковой выдаче вообще отображается на 3-4 странице поиска, то это ведёт к потерям заинтересованных клиентов.

Кажется, что это неважная мелочь, но много посетителей покинуло сайт после того как в поисковой выдаче не увидели нужного им товара из-за того что у них в запросе были использованы точки вместо запятых. Поэтому важно правильно настроить поиск.
3) Еще одна проблема, связанная с поиском — отсутствие возможности поиска по коду товара. Данный параметр является важным для профессиональных покупателей, которые знают, что ищут и хотят быстро найти необходимый продукт. Таким образом, добавление возможности поиска по коду товара увеличит удобство пользователей при поиске.


4) Теперь рассмотрим две проблемы сразу. 2 в 1)
Поисковая выдача и подсказки не соответствуют запросу.
Вбиваем запрос «станок» и в подсказках нам предлагают шкивы. Немного не то что мы ищем, не правда ли?)

Далее осуществим поиск по нашему запросу «станок». И что же нам покажет выдача?
Правильно, опять на первом экране, первые карточки это шкивы. Станки тоже есть, но ниже.

Результат, пользователь в замешательстве. Скорее всего покинет сайт.
5) Другая проблема заключается в том, что при запросе, который подпадает под несколько категорий товара, пользователи не имеют возможности выбрать нужную категорию прямо в строке поиска во время ввода запроса, нужно предложить пользователю эту возможность, для того чтобы сузить количество неподходящих результатов. Это вопрос удобства. Функция выбора категорий есть в фильтрах после осуществления поиска. Но куда удобнее отфильтровать сразу во время ввода запроса.

6) Теперь к экранам с пустой выдачей, наш анализ показал, что при пустых результатах поиска никакой информации о возможности подобрать аналог не показывается. Тут необходимы информативные сообщения, предлагающие пользователям другие варианты товаров, а также возможность обратиться к менеджеру магазина. Кроме того, на экранах «Ничего не найдено» необходимо показывать блоки «Вы недавно смотрели» или предложение обратиться за подбором, чтобы пользователи не чувствовали себя обделенными.

7) Также, были обнаружены проблемы при возврате к результатам поиска с карточки товара. Отсутствие явной надписи о возможных других результатах поиска затрудняет поиск пользователю. Тут замечание к самой ссылке на результаты поиска. Объясню: реализована такая логика в которой, если запрос совпадает с названием товара, открывается карточка этого товара со ссылкой на другие результаты по этому запросу. Так вот эту ссылку нужно делать более заметной, чтобы пользователь мог перейти к результатам, если ему вдруг был нужен не этот товар.

8) Кроме проблем, связанных с поиском, наш анализ также выявил проблемы с отображением продуктовых карточек в поисковой выдаче. Необходимо предоставлять пользователю важную информацию о продукте в превью, а также упростить процесс сравнения товаров. В результате пользователи смогут быстрее принимать решения о покупке, что приблизит магазин к цели – увеличению конверсии.

9) Еще одно замечание относится к самой строке поиска. Кнопка поиска могла бы быть бо́льшего размера и более яркой и заметной. Да, не все управляются с мышкой превосходно, некоторые не могут попасть в маленькие кнопки с первого раза)

И, наконец, онлайн магазины всё ещё не используют фильтры в поиске. Эта функция быстро и легко сортирует продукты с учетом требований покупателя, тем самым экономя время и упрощая выбор. В магазинах с большим ассортиментом продуктов на окно поиска может уйти много времени, что отпугнет покупателя и уменьшит его вероятность оформить заказ.
В конечном итоге, анализ поведения пользователей в интернет-магазинах помогает не только выявлять проблемы на сайте, но и предлагать оптимизацию, которая позволит улучшить взаимодействие пользователя и сайта. Создание удобного и интуитивно понятного интерфейса, а также обеспечение эффективной работы поиска и фильтров является критически важным для привлечения и удержания покупателей в интернет-магазинах.
Спасибо за ваше время.
4 шага проверки входных данных приложением?
Любое приложение, которое взаимодействует с внешним миром посредством каких либо интерфейсов, сталкивается с задачей фильтрации и проверки вводимой информации.
Количество разработчиков и производимых ими продуктов растёт, а их квалификация и качество падает. Моё мнение: это связано с отсутствием инженерных навыков у современных разработчиков, так как современный мир убеждает, что достаточно закончить курсы, а образование, умение структурированно мыслить и учиться новому это удел отраслевых пенсионеров.
Чтобы закрыть эту зияющую дыру, я решил написать этот небольшой ликбез.
Ниже будет описана последовательность действий для проверки входных данных, которые я сформировал исходя из личного опыта. Я не исключаю, что его можно дополнить или улучшить, либо реализовать иначе, но фундаментально вряд ли что-то изменится.
1. Проверка на наличие
Любые входные данные могу содержать как обязательные значения/поля, так и необязательные.
Эта проверка касается исключительно обязательных величин.
Приложению ресурсно выгодно отсечь неправильные входные данные, не углубляясь в ресурсозатратные проверки.
Что нужно сделать:
- проверить наличие всех обязательных значений/полей;
- если хотя бы одного значения/поля нет, то необходимо прекратить дальнейшую проверку и вернуть ответ с ошибкой.
На что приложение потратит ресурсы на этом этапе:
- на парсинг входных данных, если это необходимо;
- на проверку наличия обязательных значений/полей.
Такими минимальными затратами приложение может уже отсечь часть некорректных входных данных. В случае веб-приложения, этот высвободившийся ресурс может пригодиться во времена DOS атаки на ресурс.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных
Пример корректных данных
Всего лишь одной проверкой наличия required можно отсечь этот запрос без детальной проверки всех значений/полей.
2. Проверка на тип данных
Второй этап такой же простой как и предыдущий, и может дать не меньшую экономию ресурсов.
Входные данные состоят из значений/полей разных типов данных (речь про примитивные типы данных). Комплексные типы состоят из примитивных, следовательно, их точно так же можно проверить.
Что нужно сделать:
- проверить каждое значение/поле по его типу (string/int/uint/float/boolean);
- если хотя бы одно значение/поле имеет неожидаемый тип данных, то необходимо прекратить дальнейшую проверку и вернуть ответ с ошибкой.
Порядок проверки по типу данных следует выполнять в следующем порядке:
- обязательные значения/поля;
- наиболее часто встречаемые значения/поля при их наличии;
- все остальные при их наличии.
Пример:
Ожидаемая JSON структура аналогична как у предыдущего примера.
Пример некорректных данных
Этот этап на столько же эффективен как и предыдущий, но чутка более ресурсоёмкий.
3. Проверка на формат
Данный этап при надлежащем применении может отсечь большую часть кодовых инъекций.
Под эту проверку попадают все значения/поля, кроме типа boolean. Они уже досконально проверены на предыдущих этапах.
В чём суть:
Мы заранее знаем, что мы получим от потребителя приложения. Толи это будут какие-то числа, толи текст, или массив каких-то типов.
- если получаем int/uint/float значение и оно должно быть в рамках каких-то диапазонов или ограничений, нужно убедиться, что оно действительно так.
- если получаем string и это не свободный текст, то нужно его проверить по формату.
Способы проверки значений типа string:
- разделение на смысловые блоки и простыми логическими операциями проверяем значение (менее ресурсоёмко, но дольше в реализации);
- используем регулярные выражения (более ресурсоёмко, но быстрее в реализации в умелых руках).
Порядок проверки по типу данных следует выполнять как и на предыдущем этапе в следующей последовательности:
- обязательные значения/поля;
- наиболее часто встречаемые значения/поля при их наличии;
- все остальные при их наличии.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных
Как проверяем:
- так как поле some_field содержит свободный текст, его содержимое следует экранировать самостоятельно средствами языка для использования внутри приложения, либо средства драйверов СУБД для хранения и обработки в базе данных;
- поле kidneys должно быть в диапазоне [0, 2] (вспоминаем школьную математику и биологию, которая нафиг были не нужны ); следовательно, так как переданное значение не попадает в заданный диапазон, следует прекратить обработку и вернуть ошибку;
- поле email можно проверить двумя способами: простыми операциями и проверками или при помощи регулярных выражений. Ниже опишу оба способа проверки. По аналогии, если поле не проходит проверку, нужно вернуть обработку и вернуть ошибку.
Способы проверки поля email простыми операциями:
- убедиться, что значение содержит символ @ ;
- убедиться, что символ @ не первый и не последний;
- проверить длину email`а, она не должна превышать 320 символов ( <длинна имени 64>@ <длинна хоста 255>).
Для минимальной проверки email`а этих действия чаще всего достаточно.
Способы проверки поля email регулярным выражением:
Используя регулярное выражение ниже нужно выполнить в проверку значения
4. Логическая проверка
Этот этап, судя из регулярный новостей о поломках различных государственных/крупных коммерческих сайтов чужд разработчикам их создавшие.
Эта проверка наиболее ресурсоёмкая и вот почему: если в запросе фигурирует поле с идентификатором чего либо, нужно убедиться, что запись с данным идентификатором уже есть в информационной системе, за исключением тех запросов, которые должны эту запись создать.
- допустим, все данные хранятся в единой базе данных;
- для проверки идентификатора понадобится сделать запрос к базе данных, что требует ресурсов приложения на удержание запроса, на подключение к базе данных и на обработку запроса самой базой данных, и самое главное, может увеличить время исполнения в разы;
Как можно упростить решение и сделать его менее ресурсоёмким:
- использовать In-Memory хранение нужных идентификаторов в приложении;
- использовать быстрые кеш-машины для хранения нужных данных;
- использовать поисковые движки, которые будут в реальном времени индексировать нужные данные; использую поисковые индексы можно быстро проверять нужные индексы;
- организовывать запросы так, чтобы ресурсоёмкость запросов свести к минимуму.
Пример:
Ожидаемая JSON структура входных данных
Пример некорректных данных:
Пример потенциально корректных данных:
Но нам нужно убедиться, что пользователь с ID 1 существует и не заблокирован.
Как проверяем (простой пример с СУБД):
Допустим у нас есть некая таблица в базе данных со следующей структурой:
- нужно подключиться к базе данных;
- проверить, есть ли такой пользователь;
- у этого пользователя флаг is_available равен ли true ;
- у этого пользователя флаг is_removed равен ли true ;
- всё это несложно организовать одним запросом.
Эта простая проверка позволяет не допустить получение доступа к чужой пользовательской информации или выйти за пределы задуманной функциональности приложения.
Выводы
Из своего опыта могу сказать, что подобным списком проверок пользуются небольшое количество знакомых разработчиков, а знаю я достаточно много. Чаще всего разработчики полагаются на некий мифические фреймворки, которые за них проверят и обезопасят приложение. Могу сказать лишь одно: если бы в жизни ИТ всё было так просто, то какого чёрта специалисты имеют заработки выше рынка?