Veja esse código:
if ( isset( $_POST['cartflows-action-nonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['cartflows-action-nonce'] ) ), 'cartflows-action-nonce' ) ) {
return;
}
Esse trecho de código foi retirado de um plugin do WordPress com mais de 100 mil downloads ativos, o Cartflows ( https://wordpress.org/plugins/cartflows/ ).
Essa condição é uma validação de segurança, para evitar CSRF, serve para saber que você é você mesmo, o wp_verify_nonce verifica se você veio realmente da página anterior e não uma requisição vinda de qualquer lugar, ela guarda uma “sequência”.
Mas essa validação está errada, e esse item de segurança pode facilmente ser ultrapassado. Vale lembrar que essa não é uma falha tão grave, mas se juntar com outros erros pode ser fatal.
Esse vídeo na sequencia varre o código de todos os plugins para validar quem possue esse mesmo tipo de problema, e encontramos um total de 420 plugins possivelmente com o mesmo problema.
Vamos entender o que se passa:
Acho que todos já viram uma tabela de operadores lógicos como essa:
https://www.php.net/manual/pt_BR/language.operators.logical.php
Sempre achamos que sabemos, somos experientes e nunca erramos, então vou fazer uma pergunta e me responda de cabeça.
Como avaliamos essa variável, $_GET[‘test’]?
Devemos validar se ela existe e se o índice possui a letra a, caso contrário, pare a execução, lembrando que não pode quebrar ( Erro de Undefined ) caso não usemos ela.
Vou te dar algumas opções:
I-if( strpos($_GET['test'],'a') === false ) die();
II-if( isset($_GET['test']) && strpos($_GET['test'],'a') === false ) die();
III-if( ! isset($_GET['test']) && strpos($_GET['test'],'a') === false ) die();
IV-if( ! empty($_GET['test']) && strpos($_GET['test'],'a') === false ) die();
Resposta:
I – gera erro de Undefined.
II – se não usar o parâmetro test ele passa;
III – use ?test=bbb e ele vai passar
IV – se não usar o parâmetro test ele passa;
Resultado, somente a primeira vai funcionar, mas vai gerar Undefined, todas as outras não agirá da forma que precisamos, então nenhum resultado é o que esperamos.
Mas qual o motivo para isso acontecer tecnicamente e na cabeça dos desenvolvedores?
- _GET, _POST e _REQUEST são arrays e como todo array precisa passar por uma checagem do índice ou ele sempre vai gerar Undefined caso não exista, ou seja precisa de um isset ou empty antes.
- Nesse caso, como a “verdade do if” é para o sistema não continuar, o código tem que checar todas as validações separadamente ( com || ). Pensando de forma simples, seria como estivesse um if para cada condição.
- Muita das vezes isso ocorre porque indentificamos um Undefined depois de criar a condição e depois disso e a primeira coisa que vem a cabeça é validar se ele existe e adicionar com a primeira condição, mas vimos que não é bem assim.
Então uma das respostas correta seria.
if(! isset($_GET['test']) || strpos($_GET['test'],'a') === false ) die();
Algumas dicas para isso não acontecer:
- Atenção quando quiser usar return early, ele pode confundir as condições e qualidade pode se transformar em falha de segurança.
- Se estiver na dúvida para um return early, por segurança, crie um if para cada condição ( Pessoal que gosta de padrão não vai gostar disso ).
- Verifique todos os _POST, _GET, _REQUEST antes, caso não exista preencha variável com false. Frameworks já fazem isso.
- Teste não enviando parâmetros.
- Na maioria das vezes o empty vai servir, ele já faz o serviço do isset.
Obs:
O PHP 8 existe um método só para isso, str_contains.
if (str_contains(‘How are you’, ‘are’)) { echo ‘true’; }
References:
https://www.php.net/manual/en/index.php
Tahnks for revision by Thiago Dieb and Leonn Leite