Proteção contra ataques de cross-site scripting (CSRF)
Introdução
Falsificação de requisição entre sites é um tipo de exploração maliciosa em que comandos não autorizados são executados em nome de um usuário autenticado. Felizmente, o Laravel facilita a proteção da sua aplicação contra ataques de falsificação de pedido de site diferente(CSRF).
Uma explicação da vulnerabilidade
Caso você não esteja familiarizado com as solicitações de falsificação entre sites, vamos discutir um exemplo de como essa vulnerabilidade pode ser explorada. Imagine que o seu aplicativo tenha uma rota de /user/email
, que aceite uma solicitação POST
para alterar o endereço do email do usuário autenticado. Muito provavelmente, esta rota espera um campo de entrada email
para conter o endereço de e-mail que o usuário gostaria de começar a usar.
Sem proteção contra CSRF, um site maligno poderia criar um formulário HTML que aponta para a rota de sua aplicação (/_user/email
) e enviar o endereço de e-mail do usuário malicioso:
<form action="https://your-application.com/user/email" method="POST">
<input type="email" value="malicious-email@example.com">
</form>
<script>
document.forms[0].submit();
</script>
Se o site mal-intencionado enviar automaticamente o formulário quando a página for carregada, será necessário apenas persuadir um utilizador não desconfiado da sua aplicação para visitar o site e o endereço de correio eletrónico será alterado na aplicação.
Para impedir essa vulnerabilidade, precisamos inspecionar cada solicitação de entrada POST
, PUT
, PATCH
ou DELETE
para um valor secreto da sessão que o aplicativo malicioso não tem acesso.
Evitar requisições CSRF
O Laravel gera automaticamente um "token" CSRF para cada sessão de usuário ativo gerenciada pela aplicação. Este token é utilizado para verificar se o utilizador autenticado é realmente a pessoa que está a fazer os pedidos à aplicação. Uma vez que este token é armazenado na sessão do utilizador altera-se sempre que a sessão for regenerada, uma aplicação maliciosa não tem acesso ao mesmo.
O token de CSRF da sessão atual pode ser acessado por meio da sessão da requisição ou por meio do auxílio de função csrf_token
:
use Illuminate\Http\Request;
Route::get('/token', function (Request $request) {
$token = $request->session()->token();
$token = csrf_token();
// ...
});
Sempre que definir um formulário HTML "POST", "PUT", "PATCH" ou "DELETE" na sua aplicação, você deve incluir no formulário um campo oculto _token
do CSRF para que a middleware de proteção contra ataques XSS possa validar o pedido. Para conveniência, pode utilizar a directiva @csrf
do Blade para gerar o campo de entrada do token:
<form method="POST" action="/profile">
@csrf
<!-- Equivalent to... -->
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
O Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
middleware, que está incluído no grupo de middleware web
por padrão, verificará automaticamente se o token na solicitação input corresponde ao token armazenado na sessão. Quando esses dois tokens coincidem, sabemos que o usuário autenticado é quem inicia a solicitação.
Tokens de CSRF e SPAs
Se você estiver construindo um SPA que utiliza o Laravel como um back-end de API, consulte a documentação do Laravel Sanctum para obter informações sobre autenticação com sua API e proteção contra vulnerabilidades CSRF.
Excluindo os URIs da proteção contra a CSRF
Às vezes, você pode desejar excluir um conjunto de URI da proteção contra CSRF. Por exemplo, se estiver a utilizar o Stripe para efetuar pagamentos e utilizar o sistema webhook da Stripe, terá de excluir a rota do seu manipulador de webhooks da proteção contra CSRF, pois a Stripe não saberá que token CSRF enviar para as suas rotas.
Normalmente, você deve colocar este tipo de rotas fora do grupo de middleware web
que o Laravel aplica a todas as rotas no arquivo routes/web.php
. Porém, também é possível excluir rotas específicas, fornecendo seus URIs para o método validateCsrfTokens
em seu arquivo bootstrap/app.php
:
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
]);
})
NOTA
Por conveniência, o middleware CSRF é desativado automaticamente para todas as rotas ao executar testes.
X-CSRF-TOKEN
Além do control do token CSRF como um parâmetro POST, o middleware Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
, que é incluído no grupo de middlewares web
por padrão, também irá verificar a secção do cabeçalho da solicitação X-CSRF-TOKEN
. Podia, por exemplo, armazenar o token numa tag HTML:
<meta name="csrf-token" content="{{ csrf_token() }}">
Em seguida, você pode instruir uma biblioteca como o jQuery para adicionar automaticamente o token a todas as cabeçalhos de solicitação. Isso proporciona uma proteção CSRF simples e conveniente para seu aplicativo baseado em AJAX usando tecnologia JavaScript antiga:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
X-XSRF-TOKEN
O Laravel armazena o atual token CSRF em um cookie encriptado chamado "XSRF-TOKEN". Este cookie é incluído com cada resposta gerada pelo framework. Você pode usar o valor do cookie para definir a solicitação de cabeçalho X-XSRF-TOKEN
.
Este cookie é enviado principalmente como um recurso para desenvolvedores, já que alguns frameworks e bibliotecas de JavaScript, como Angular e Axios, automaticamente colocam seu valor no cabeçalho X-XSRF-TOKEN
em solicitações do mesmo domínio.
NOTA
Por padrão, o arquivo resources/js/bootstrap.js
inclui a biblioteca de HTTP Axios que envia automaticamente o cabeçalho X-XSRF-TOKEN
.