Привет, я Валерио Барбера, инженер-программист, основатель и технический директор компании Inspector.
Валидация данных является одной из фундаментальных функций в любом приложении, и это то, чем разработчики манипулируют почти каждый день. Ценность программного обеспечения для пользователей часто зависит от качества данных, которыми оно способно управлять. Laravel поставляется с большим количеством предопределенных правил валидации, которые вы можете сразу же использовать в своих контроллерах.
В любом случае, работая над бэкендом Inspector, мы определили некоторые аспекты проверки входящих данных, которые влияют на безопасность и надежность приложения, а также благодаря пользовательским правилам вы можете легко расширить уровень валидации вашего приложения функциями, предоставляемыми внешними сервисами.
Позвольте мне начать с небольшого контекста, чтобы прояснить, какую роль играет слой валидации в бэкенд-сервисе, а затем я покажу вам наши реализации.
Валидационный слой Laravel
Целостность данных и валидация — важные аспекты веб-разработки, поскольку они определяют состояние приложения. Если данные неверны, приложение ведет себя неправильно.
Всегда важно проверять данные не только перед сохранением их в базе данных, но и перед выполнением любых действий.
В жизненном цикле запроса Laravel HTTP-запрос, отправленный клиентом, сначала проходит через промежуточное ПО. Промежуточное ПО имеет дело с различными аспектами аутентификации и безопасности.
Теперь, прежде чем запрос попадет в приложение, данные, которые он несет, должны быть проверены.
В Laravel есть два способа выполнить проверку данных: Внутри контроллеров или с помощью запросов Form.
Валидация в контроллере
Самый простой способ валидации — это выполнение ее непосредственно в контроллере. В начале каждого метода контроллера вы можете сначала выполнить валидацию данных:
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class UserController extends Controller
{
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|min:3',
'email' => 'required|email|min:6',
]);
// here we know data are valid so we can pass them to database or other services
}
}
Laravel позаботится о том, чтобы вернуть клиенту код ответа 422, если данные не являются достоверными.
Используйте запросы формы
Если ваши правила валидации слишком сложны, вы можете захотеть инкапсулировать их в многократно используемые классы, чтобы не перегружать контроллер.
Laravel предоставляет возможность обернуть валидацию в специальный компонент под названием FormRequest.
Сначала создайте класс запроса формы:
php artisan make:request StoreUserRequest
Затем перенесите логику валидации в метод rules класса запроса:
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class StoreUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|min:3',
'email' => 'required|email|min:6',
];
}
}
Вы можете вписать этот новый класс запроса в метод контроллера вместо исходного класса запроса, чтобы Laravel автоматически применил правила валидации и удалил утверждение валидации:
<?php
namespace AppHttpControllers;
use AppHttpRequestsStoreUserRequest;
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
// here we know data are valid so we can pass them to database or other services
}
}
Пользовательские правила валидации
Laravel предоставил действительно хорошо разработанный слой валидации. Его можно легко расширить, применяя пользовательские правила для повторного использования в коде или для расширения возможностей валидации с помощью внешних сервисов.
Позвольте мне показать вам реальный пример с одним из пользовательских правил, которое мы реализовали в Inspector.
Сначала создайте класс, представляющий правило валидации в Laravel:
php artisan make:rule SecurePassword
Идея заключается в том, чтобы проверить, входит ли пароль в список известных небезопасных паролей. Если да, то он не пройдет проверку, вынуждая пользователя использовать менее распространенную строку.
<?php
namespace AppRules;
use IlluminateContractsValidationRule;
class SecurePassword implements Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return !in_array($value, [
'picture1',
'password',
'password1',
'12345678',
'111111',
...
]);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'The chosen password is unsecure. Try again with a less common string.';
}
}
Интеграция с внешними сервисами
Говоря о проверке данных, следует отметить, что существует множество SaaS-сервисов, которые могут привнести новые возможности в ваш уровень проверки с точки зрения безопасности и надежности собранных данных.
Я рекомендую вам взглянуть на apilayer.com, который предоставляет отличный набор REST-сервисов для работы с данными.
В Inspector мы используем API mailboxlayer.com для проверки электронной почты. Сервис также способен обнаруживать поддельные адреса электронной почты, временные адреса и фактическое существование адреса электронной почты с помощью MX-записей и SMTP.
Добавьте два свойства конфигурации для хранения api ключей новых сервисов в файл config/service.php
:
return [
...,
'mailboxlayer' => [
'key' => env('MAILBOXLAYER_KEY'),
],
'vatlayer' => [
'key' => env('VATLAYER_KEY'),
],
];
Создайте пользовательское правило:
php artisan make:rule EmailSpam
Вот полный код правила:
<?php
namespace AppRules;
use IlluminateContractsValidationRule;
class EmailSpam implements Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
if (app()->environment('local')) {
return true;
}
return !config('services.mailboxlayer.key') || $this->check($value);
}
/**
* Perform email check.
*
* @param string $email
* @return bool
*/
protected function check(string $email): bool
{
try{
$response = file_get_contents('https://apilayer.net/api/check?'.http_build_query([
'access_key' => config('services.mailboxlayer.key'),
'email' => '[mailbox-layer-account-email]',
'smtp' => 1,
]));
$response = json_decode($response, true);
return $response['format_valid'] && !$response['disposable'];
} catch (Exception $exception) {
report($exception);
if (app()->environment('local')) {
return false;
}
// Don't block production environment in case of apilayer error
return true;
}
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'Invalid email address.';
}
}
Советы и рекомендации
Проверяйте границы
Основываясь на своем опыте, я могу посоветовать вам всегда проверять не только минимальный размер входящих полей, но и максимальный.
Не ждите ошибок базы данных, которые усекают слишком длинные строки, и помогите своим пользователям понять границы каждого поля по сообщениям об ошибках, возвращаемым при валидации.
Запрашивайте текущий пароль
Каждое критическое действие должно требовать подтверждения пароля.
Вы всегда должны просить пользователя ввести текущий пароль для авторизации действий, которые могут поставить под угрозу доступность учетной записи, например, изменение электронной почты и изменение пароля.
Эта функция повысит уровень безопасности, поскольку, имея физический доступ к компьютеру с открытой на экране приборной панелью Inspector, злоумышленник не сможет изменить учетные данные доступа, не зная текущего пароля. Он не сможет закрыть вам доступ.
Вот наша реализация текущей проверки пароля:
<?php
namespace AppRules;
use IlluminateContractsValidationRule;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesHash;
class CurrentPassword implements Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return Hash::check($value, Auth::user()->password);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'Your current password is incorrect.';
}
}
Новичок в Inspector?
Вы ищете «управляемый кодом» инструмент мониторинга для автоматического выявления технических проблем в ваших приложениях?
Получите среду мониторинга, специально разработанную для разработчиков программного обеспечения и не требующую конфигурации сервера или инфраструктуры.
Благодаря Inspector у вас никогда не будет необходимости устанавливать что-то на уровне сервера или выполнять сложную конфигурацию в вашей облачной инфраструктуре для мониторинга вашего приложения в режиме реального времени.
Inspector работает с легковесной программной библиотекой, которую вы можете установить в свое приложение, как и любые другие зависимости, в зависимости от технологии, которую вы используете для разработки бэкенда. Ознакомьтесь с поддерживаемыми технологиями на нашем GitHub (https://github.com/inspector-apm).
Посетите наш сайт для получения более подробной информации: https://inspector.dev/laravel/