Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Wallace Maxters

Segurança no método post

Recommended Posts

Bem, é o seguinte:

 

Quando comecei a trabalhar com PHP, trabalhava numa empresa onde me deparei com um código semelhante a esse:

 

if( isset($_POST['submit']) ){echo $_POST['nome'];echo '<br>';echo $_POST['email'];} ?> <form action='' method='post'><input type='text' name='nome'><input type='text' name='email'><input type='submit' name='submit'></form>

(é só um exemplo, mas a maneira de trabalhar com o post foi essa mesma)

 

 

Certo. Aqui vai uma questão. Quando usei a ferramenta do desenvolvedor do Google Chrome e mudei o nome "email" do input para um outro nome qualquer e dei um submit, como esperado, apareceu o seguinte erro:

Notice: Undefined index: email in C:\xampp\htdocs\teste\index.php on line 8

 

Qual maneira vocês sugeririam para tratar o problema?

 

pensei em...

 

 <?php  if( isset($_POST['submit']) && array_key_exists('email', $_POST) && array_key_exists('nome', $_POST)){echo $_POST['nome'];echo '<br>';echo $_POST['email'];} ?> <form action='' method='post'><input type='text' name='nome'><input type='text' name='email'><input type='submit' name='submit'></form>

... Mas se fossem muitos inputs, teríamos um "if quilométrico", e não seria muito elegante.

 

 

Como lidar com esse "probleminha" de uma maneira mais elegante?

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ué, use o isset mesmo, lembrando que o valor do Post Request deve ser o mesmo name do input.

if( isset( $_POST['NAME-DO-INPUT'] ) and isset( $_POST['NAME-DO-INPUT-2'] ) //etc

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Ué, use o isset mesmo, lembrando que o valor do Post Request deve ser o mesmo name do input.

if( isset( $_POST['NAME-DO-INPUT'] ) and isset( $_POST['NAME-DO-INPUT-2'] ) //etc

Eu sei que o valor deve ser o mesmo do input e também do isset(), mas a questão é "resolver de maneira mais apropriada". Pois, se você tivesse 23 inputs( não é exagero, estou num projeto que tem mais de 20 ), eu fazia um isset para cada um?

Com certeza tem um jeito melhor de resolver isso.

 

 

Imagina como ficaria um if com 20 isset()?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tem que ver exatamente o que você quer validar, porque validar um número de telefone, e-mail, data de nascimento, etc, terá que ser feito de forma individual, se o problema é apenas validar se o campo existe, está em branco e se todos os campos esperados foram enviados, use um array com o nome dos campos, um foreach para ler todo o post enviado, a cada volta do laço você verifica com in_array se o nome enviado está no array, se não estiver algo não esperado foi enviado, se estiver você remove esse elemento do array, se após o fim do foreach ainda restarem elementos no array significa que nem tudo que era esperado foi enviado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tem que ver exatamente o que você quer validar, porque validar um número de telefone, e-mail, data de nascimento, etc, terá que ser feito de forma individual, se o problema é apenas validar se o campo existe, está em branco e se todos os campos esperados foram enviados, use um array com o nome dos campos, um foreach para ler todo o post enviado, a cada volta do laço você verifica com in_array se o nome enviado está no array, se não estiver algo não esperado foi enviado, se estiver você remove esse elemento do array, se após o fim do foreach ainda restarem elementos no array significa que nem tudo que era esperado foi enviado.

 

Pensei em fazer assim:

 

$permitidos = array('email', 'nome');  if( isset($_POST['submit']) && ! array_diff($permitidos,array_keys($_POST))  ){echo $_POST['nome'];echo '<br>';echo $_POST['email'];} ?> <form action='' method='post'><input type='text' name='nome'><input type='text' name='email'><input type='submit' name='submit'></form>

 

O array diff retorna dos valores que não existem na comparação dos dois (ou alguma coisa assim).

aí, é só verificar se ele está retornando vazio, pois se for vazio é que todas as keys do $_POST "bateram" com os valores de $permitidos

Se alguém tiver uma maneira melhor e menor, aceito a sugestão :)

 

Tem que ver exatamente o que você quer validar, porque validar um número de telefone, e-mail, data de nascimento, etc, terá que ser feito de forma individual, se o problema é apenas validar se o campo existe, está em branco e se todos os campos esperados foram enviados, use um array com o nome dos campos, um foreach para ler todo o post enviado, a cada volta do laço você verifica com in_array se o nome enviado está no array, se não estiver algo não esperado foi enviado, se estiver você remove esse elemento do array, se após o fim do foreach ainda restarem elementos no array significa que nem tudo que era esperado foi enviado.

A questão não é a validação, mas sim de o cara apagar um name do input do formulário, por exemplo, e enviar.

É claro que nunca se deve colocar um sistema pra rodar com error_reporting ativado (como é o caso do meu primeiro exemplo).

Compartilhar este post


Link para o post
Compartilhar em outros sites
if($_SERVER['REQUEST_METHOD'] == 'POST') {
//o que vai acontecer aqui
}else{
//o que vai ocorrer caso contrário
}

Agora pra evitar Xss e SQL Injection deve tratar os dados recebidos do post, por exemplo striptags, htmlentities e outros que existe podem ser visto em:

 

http://php.net/

 

@EDIT

 

Dei uma lida mais a fundo no que você escreveu, esse erro é por que a variável email não existe e você ta tentando receber os dados dela, por mais que você valide isso é impossível de se reter, outra coisa é o fato que não da pra fazer injection por essa ferramenta, já que os dados precisam ir pro servidor, e assim o script é interrompido.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A questão não é a validação, mas sim de o cara apagar um name do input do formulário, por exemplo, e enviar.

É claro que nunca se deve colocar um sistema pra rodar com error_reporting ativado (como é o caso do meu primeiro exemplo).

Você vai usar isso com BD? Se sim coloque o campo como not null, se o cara apagar o name não vai chegar nada e o insert/update vai retornar erro, se for um select/delete não vai encontar o dado. Tirando isto, a pessoa manipular o name de um form é algo que não trás nenhum prejuízo a não ser a própria pessoa.

Compartilhar este post


Link para o post
Compartilhar em outros sites

set_error_handler

 

set_error_handler(function ($level, $message) {
    if (!preg_match('/undefined index/', $message)) {
        return false;
    }
    echo "Por favor, não manipule nossos formulários!";
    return true;
}, E_NOTICE);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // toda a lógica do seu formulário vem aqui
}

// Quando você não precisar mais dessa "segurança"...
restore_error_handler();

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

set_error_handler

 

set_error_handler(function ($level, $message) {
    if (!preg_match('/undefined index/', $message)) {
        return false;
    }
    echo "Por favor, não manipule nossos formulários!";
    return true;
}, E_NOTICE);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // toda a lógica do seu formulário vem aqui
}

// Quando você não precisar mais dessa "segurança"...
restore_error_handler();

 

Essa eu não conhecia. Boa!

 

 

if($_SERVER['REQUEST_METHOD'] == 'POST') {
//o que vai acontecer aqui
}else{
//o que vai ocorrer caso contrário
}

Agora pra evitar Xss e SQL Injection deve tratar os dados recebidos do post, por exemplo striptags, htmlentities e outros que existe podem ser visto em:

 

http://php.net/

 

@EDIT

 

Dei uma lida mais a fundo no que você escreveu, esse erro é por que a variável email não existe e você ta tentando receber os dados dela, por mais que você valide isso é impossível de se reter, outra coisa é o fato que não da pra fazer injection por essa ferramenta, já que os dados precisam ir pro servidor, e assim o script é interrompido.

Tá, mas se seu código tivesse um echo num $_POST['email] depois do submit, daria erro, porque a chave do array não existe.

 

Eu geralmente evito usar $_SERVER['REQUEST_METHOD'] == 'POST' porque as vezes temos que lidar com códigos que tem mais de um formulário (com "submit name " diferentes) na mesma página. Só se eu tiver certeza de usar um formulário só.

 

E aí vem aquela questão: Qual submit estou verificando com "$_SERVER['REQUEST_METHOD'] == 'POST' "?

Eu teria que colocar outro if dentro dessa verificação, pois já trabalhei com códigos que o programador setou um [submit name=logar] e um [submit name=esqueci] no mesmo formulário.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Muito simples:

 

if($_SERVER['REQUEST_METHOD'] == 'POST') {
//primeiro form
if(isset($_POST['nome_do_submit'])) {

}else{ }
//psegundo form
if(isset($_POST['nome_do_submit2'])) {

}else{ }

}

Voce usa o REQUEST_SERVER só pra saber se realmente algum post foi enviado depois você filtra...

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Wallace Maxters

 

Primeiro: garanta que não tenha erros no seu código. Você mudar uma variavel em um lugar, ter que mudar em outro, é acoplamento. Nesse caso de HTML + PHP é algo básico.

 

Segundo: as configurações de erro do servidor de produção devem ser diferentes das configurações do servidor de desenvolvimento. Enquanto o servidor de desenvolvimento mostra todos os erros possíveis na tela, o de produção esconde.

 

Terceiro: se vc não souber configurar seu servidor de produção corretamente, aprenda.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Uma requisição POST não significa que os campos estarão preenchidos. Aliás, campos são apenas definidos no formulário, que é apenas uma GUI.

 

Já viu o Respect\Validation?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Simples e acabando com o problema.

 

Se a pessoa for fazer qualquer invasão do sistema ele vai usar seu formulário diretamente sem mudar nada ou usar outros métodos, PHP é tratado do lado Servidor (client side) então sendo assim qualquer coisa que ele altere se seu script não estiver preparado pra receber aquele dado ele não vai passar disso, como o undefined index (script pauso ali).

 

Então pra evitar qualquer coisa no post deve-se tratar as variáveis com os dados recebidos do mesmo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu geralmente evito usar $_SERVER['REQUEST_METHOD'] == 'POST' porque as vezes temos que lidar com códigos que tem mais de um formulário (com "submit name " diferentes) na mesma página. Só se eu tiver certeza de usar um formulário só.

 

E aí vem aquela questão: Qual submit estou verificando com "$_SERVER['REQUEST_METHOD'] == 'POST' "?

Tá confundindo as bolas, amigo. [inline]REQUEST_METHOD[/inline] informa, apenas, se o cara chegou até aquele script através de um [inline]<form method="post" ...[/inline] - ou forjando uma requisição. Só isso. Ponto. Pra saber qual formulário foi enviado, já foram dadas dicas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

#1

 

É basicamente o que faz um framework.

vc já deve ter ouvido falar de Cakephp, laravel, zendFramework, CodeIgniter, entre outros..

 

 

 

Precisa criar um conjunto de regras para cada campo e uma rotina que itere as regras do objeto.. exemplo:

 

// os campos com suas respectivas regras de validação.
// os índices do array $fields, são os nomes dos campos.
// pode ter mais de 10 milhões de campos que a rotina abaixo fará todo o tratamento baseado nas regras de cada campo... Sem necessidade em escrever 10 milhões de if( isset() )
// vc só adiciona os campos nesse array $fields:

$fields = array(
    'foo' => array( 'validation' => 'text', 'required' = true, 'value' = null ),
    'bar' => array( 'validation' => 'int', 'required' = false, 'value' = null ),
    'bar2' => array( 'validation' => 'email', 'required' = true, 'value' = null ),
    'bar3' => array( 'validation' => 'url', 'required' = false, 'value' = null ),
)



$fields_errors = array();

if( isset( $_POST ) and !empty( $_POST ) )
{
    foreach( $fields as $k => $v )
    {
        // quer dizer que esse campo é obrigatório, portanto, precisa verificar se foi enviado algo
        if( $v['required'] )
        {
            if( isset( $_POST[$k] ) )
            {
                $fields[$k]['value'] = $v; // recebe o valor provindo do post
                // até aqui recebeu de boa.. então prossiga com outros requisitos como filtros, validação de tamanho da string, etc..
                
                switch( $fields[$k]['validation'] )
                {
                    case 'text':
                        // normalmente não tem muito o que verificar.. texto é texto..
                    break;
                    case 'int':
                        // verifique se possui somente números inteiros.
                    break;
                }


            }else{
                $fields_errors[$k]['required'] = true; // não recebeu valor.. retornar mensagem de preenchimento obrigatório
            }
        }
    }
}

// não encontrou erros, então prossegue outros processos
if( empty( $fields_errors ) )
{
    
}else{
    // encontrou erros.. então prossiga tratando os erros..
    print_r( $fields_errors );
}

 

 

 

O exemplo é bastante simplório..

 

 

A princípio é simples criar algo básico mas se tornará mais complexo quando implementar tratamentos recursivos em arrays multidimensionais.

 

 

 

Perceba ainda no exemplo acima que estamos capturando somente os dados enviados pelo método POST.

Então para o método GET teremos que escrever tudo de novo ?

 

Aí entra umas mágicas do PHP..

 

 

$method = $_SERVER['REQUEST_METHOD'];
$parameters = $GLOBALS['_' . $method];

Ao invés de chamar um método estaticamente

 

 

if( isset( $_POST ) and !empty( $_POST ) )
{

poderá chamar dinamicamente

 

$method = $_SERVER['REQUEST_METHOD'];
$parameters = $GLOBALS['_' . $method];

if( isset( $parameters ) and !empty( $parameters ) )
{

independente de ter vindo por POST ou GET, já pega automaticamente.

 

 

sacou?

 

com o tempo vc vai aprimorando..

Compartilhar este post


Link para o post
Compartilhar em outros sites

Só complementando uma coisinha:

Se você quer saber se o formulário veio do seu host ou alguém o clonou, é simples:

if( isset( $_SERVER['HTTP_REFERER'] )and !stristr( $_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'] ) ){
    //ERROR
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Muito simples:

 

if($_SERVER['REQUEST_METHOD'] == 'POST') {
//primeiro form
if(isset($_POST['nome_do_submit'])) {

}else{ }
//psegundo form
if(isset($_POST['nome_do_submit2'])) {

}else{ }

}

Voce usa o REQUEST_SERVER só pra saber se realmente algum post foi enviado depois você filtra...

Mas ainda sim, se eu enviasse, por exemplo, apenas o post "nome_do_submit1" via PostMan do Google Chrome, como não teriam as outras chave do post, resultariam em erro.

A questão inicial era realmente criar uma lista de chaves permitidas e checar se vieram todas do formulário.

 

#1

 

É basicamente o que faz um framework.

vc já deve ter ouvido falar de Cakephp, laravel, zendFramework, CodeIgniter, entre outros..

 

Não só já ouvi falar, mas uso Laravel, Codeigniter e Cakephp.

O problema é que o código que citei acima não era tão bem estruturado como o de um framework (era tudo na unha, irmão!) e aí requer soluções na unha também.

 

Uma requisição POST não significa que os campos estarão preenchidos. Aliás, campos são apenas definidos no formulário, que é apenas uma GUI.

 

Já viu o Respect\Validation?

Não ainda, mas estou dando uma olhada agora.

 

Valeu!

 

Primeiro: garanta que não tenha erros no seu código...

é exatamente isso que eu queria. Tentei verificar com in_array() pra saber se contem exatamente as keys do post numa outra variável de verificação qualquer (o manual do php fala que o primeiro parâmentro de in_array é mixed, tentei um array. Mas agora sei que MIXED não quer dizer "Qualquer coisa");

 

 

Segundo: as configurações de erro do servidor de produção devem ser diferentes das configurações do servidor de desenvolvimento. Enquanto o servidor de desenvolvimento mostra todos os erros possíveis na tela, o de produção esconde.

 

Compreendo esse tipo de situação. O sistema tinha os erros desabilitados. Levantei essa questão pra saber se tinha um jeito de resolver isso, pois aproveitaram-se da desabilitação do erro pra esconder erros em foreach, variáveis não existentes e outros trem (mas quando dava pau mostrava dados do banco de dados, adianta?)

Como aprendi aqui no fórum (e também já fazia esse tipo de prática), sempre é bom procurar uma maneira de resolver o erro, ao invés de deixá-lo por debaixo dos panos (entenda @ ou error_repoting(0), kkkk).

Compartilhar este post


Link para o post
Compartilhar em outros sites
Não só já ouvi falar, mas uso Laravel, Codeigniter e Cakephp.
O problema é que o código que citei acima não era tão bem estruturado como o de um framework (era tudo na unha, irmão!)  e aí requer soluções na unha também.

 

#18

o code no post #15 foi feito na unha! irmão!

 

solidariedade_santa.jpg

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Não só já ouvi falar, mas uso Laravel, Codeigniter e Cakephp.
O problema é que o código que citei acima não era tão bem estruturado como o de um framework (era tudo na unha, irmão!)  e aí requer soluções na unha também.

 

#18

o code no post #15 foi feito na unha! irmão!

 

solidariedade_santa.jpg

 

kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.