Cursos Magento

Contornando proteção de CSRF no Magento 2

,

Publicado em 27 de agosto de 2019

O Magento 2.3.0 trouxe um novo recurso a fim de evitar ataques CSRF (Cross-Site Request Forgery). No entanto, ele trouxe também uma dor de cabeça para módulos que recebem chamadas externas e integrações e terceiros.

O que é CSRF?

O termo Cross-site faz referência a uma vulnerabilidade entre dois ou mais sites. Ou seja, trata-se de um tipo de ataque que envolve outro site e não apenas o seu.

Já o termo Request quer dizer “Requisição”, e Forjure quer dizer “Forjar”.

Sendo assim, trata-se de um ataque onde uma requisição é feita para o seu site mas sem necessariamente vir dele. Em geral esta é uma requisição de formulário, como login ou mesmo checkout.

Exemplo

Imagine que você está logado no seu banco, e ao mesmo tempo acessa o sitedohacker.com.br. No site do hacker, um formulário é enviado automaticamente para seu banco contendo os dados de uma transferência bancária, com todos os dados do formulário de transferência preenchidos.

Fique tranquilo. Provavelmente todos os bancos já adotaram dezenas de formas de se proteger disso.

O Magento também, e não foi ontem que isso aconteceu.

Proteção contra CSRF automática no Magento 2.3.0 e superior

A partir do Magento 2.3 toda requisição do tipo POST que não for uma requisição ajax, deve conter o parâmetro form_key.

A validação ocorre em \Magento\Framework\App\Request\CsrfValidator da seguinte forma:

    private function validateRequest(
        HttpRequest $request,
        ActionInterface $action
    ): bool {
        $valid = null;
        if ($action instanceof CsrfAwareActionInterface) {
            $valid = $action->validateForCsrf($request);
        }
        if ($valid === null) {
            $valid = !$request->isPost()
                || $request->isXmlHttpRequest()
                || $this->formKeyValidator->validate($request);
        }

        return $valid;
    }

O problema

Todo e qualquer módulo que receba requisições externas com dados enviados via POST param de funcionar. Ao invés de ter a requisição chegando ao Controller, o cliente é redirecionado (HTTP 302).

Isso impacta diretamente integrações e notificações enviadas por meios de pagamento.

Se eu soubesse disso antes, não teria esperado tanto para perceber que meu módulo do PagSeguro parou de tratar notificações enviadas pelo PagSeguro. 🙁

Notificações do PagSeguro não chegam na loja

A solução (Desabilitando a validação)

Como não temos como gerar o form_key para nossos integradores, o jeito é desabilitar esta validação no nosso Controller.

De acordo com as orientações da Magento, isso é feito implementando a classe CsrfAwareActionInterface no nosso Controller. Eis um exemplo:

class Index extends \Magento\Framework\App\Action\Action implements CsrfAwareActionInterface
{
/* (...) */
    /**
     * Create exception in case CSRF validation failed.
     * Return null if default exception will suffice.
     *
     * @param RequestInterface $request
     *
     * @return InvalidRequestException|null
     */
    public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
    {
        return null;
    }

    /**
     * Perform custom request validation.
     * Return null if default validation is needed.
     *
     * @param RequestInterface $request
     *
     * @return bool|null
     */
    public function validateForCsrf(RequestInterface $request): ?bool
    {
        return true;
    }
}

Desta forma, as requisições do tipo POST que não são AJAX estarão livres da validação CSRF do Magento 2.3 em diante.

No entanto…

Seu módulo deixará de ser compatível com qualquer versão inferior ao Magento 2.3.0, quando a interface acima foi implementada.

Conclusão

Esta foi uma medida bem eficiente encontrada pela Magento de realmente proteger lojas e módulos contra ataques deste tipo.

No entanto, a compatibilidade com versões anteriores novamente não foi mantida. Eventualmente você terá módulos quebrando versões antigas de implementações Magento.

No momento que escrevo este artigo, não encontrei uma forma muito amigável de implementar uma compatibilidade com versões anteriores a 2.3.0.

Uma implementação usando Plugins pode ser vista nesta thread no StackOverflow. Embora esta implementação mantenha a compatibilidade e esteja dentro dos padrões, preferi optar pela opção fornecida pela Magento e usada por módulos nativos como Amazon Pay.

Últimos posts por Ricardo Martins (exibir todos)
Comentários

Deixe seu comentário

[fbcomments url="https://www.magenteiro.com/blog/magento-2/desabilitar-csrf-no-controller/"]