Links encriptados no PHP

junho 11th, 2008 by caferrari Leave a reply »

Nesse post vou exemplificar como utilizar a classe XOR exemplificada no post Operador XOR no PHP para criação de URLs encriptadas usando uma espécie de checksum que irá impedir que alguem possa alrera-la. as vantagens dessa técnica são:

  • URLs camufladas
  • PHP camuflado
  • Variáveis passadas pela URL sempre válidas
  • Impossibilidade de Modificação da querystring manualmente

Aqui está o exemplo de hoje: http://ferrari.eti.br/exemplos/fw1

Esse exemplo utiliza jSon, se você não sabe o que é, veja aqui.

Para começar, vamos criar o arquivo: includes/classes/crypt.php e colocar o código do post: Operador XOR no PHP.

Depois criaremos a nossa classe mais importante: includes/classes/link.php e vamos edita-lá:

// incluímos a classe de criptografia
require_once "crypt.php";
 
// Variavel global similar a $_POST, porém sua função é
// armazenar os valores passados pela querystring
$_PAR = array();
 
class Link {
     // Variável que armazena a chave do checksum
     static $chave = "chavedockecksum";
 
     // Variável que armazena o link
     var $link = '';
 
     // construtor, os parâmetros são simples
     // pagina = arquovo php a ser chamado
     // parametros: parâmetros da chamada ex: "id=10&tipo=noticia"
     function Link($pagina='', $parametros=''){
          // chama o método responsável pela criação do link
          // repassando os parâmetros
          $this->link = $this->criaLink($pagina, $parametros);
 
          // retorna o link encriptado
          return $this->link;
     }
 
     static function criaLink($pagina='', $parametros=''){
          // transforma os parâmetros em um array associativo
          parse_str($parametros, $p);
 
          // adiciono nesse array na posição "_pagina" o arquivo php
          $p["_pagina"] = $pagina;
 
          // Aqui eu adiciono uma chave calculada a partir do que tem no array $p
          // porém adiciono somente os 5 primeiros caracteres para encurtar a chave
          // esse será o parâmetro responsável por garantir a integridade
          // da informação passada
          $p["_check"] = substr(crypt(json_encode($p), Link::$chave), 0, 5);
 
         // retornamos a URL encriptando a versão codificada em json dela.
         // rootvirtual é a constante que diz qual o root do site,
         // explicarei mais abaixo de onde ela vem
         return rootvirtual . "?" . Crypt::Encrypt(json_encode($p));
     }
 
     static function trataQuery(){
          // verifica a existência de query-string e adiciona ela na variável $q
          if ($q = $_SERVER['QUERY_STRING']){
               // decodifica a string
               $p = json_decode(Crypt::Decrypt($q), true);
                    // se o retorno for um array, quer dizer que a query é parcialmente válida
                    if (is_array($p) && isset($p["_check"])){
                        // carrega a chave do vetor
                        $chave = $p["_check"];
                        // remove a chave do vetor
                        unset($p["_check"]);
                        // recalcula a chave e verifica se é diferente a chave passada
                        if (substr(crypt(json_encode($p), Link::$chave), 0, 5) != $chave)
                             // Se for, a requisição eh redirecionada para o index.
                             header ("Location: " . rootvirtual);
                        else{
                             // se for válida é criada a variável global _PAR e o vetor
                             // de parâmetros é jogado nela
                             $GLOBALS["_PAR"] = $p;
                             // sai da função
                             return true;
                        }
               }else {
                     // se não for um vetor, houve modificação da url, e a requisição
                     // é enviada para o index
                     header ("Location: " . rootvirtual);
               }
               // termina a execução e redireciona
               die();
          }
     }
}

Agora vamos para a criação de três arquivos base do site e partir para um exemplo funcional.

o arquivo: includes/config.php irá armazenar as configurações básicas do site:

// Root no servidor do site
define ("rootfisico", "/var/www/fw/");
 
// Pasta do site no servidor
define ("rootvirtual", "/fw/");
 
// As linhas abaixo são a parte interessante do sistema, pra que usar chaves
// fixas se podemos definidas randomicamente a cada acesso ao sistema?
// assim, uma url usada por uma pessoa só será valida pra ela naquele acesso
 
if (!isset($_SESSION["cryptKey"])) $_SESSION["cryptKey"] = crypt(uniqid());
if (!isset($_SESSION["cryptKey2"])) $_SESSION["cryptKey2"] = crypt(uniqid());
 
Crypt::$chave = $_SESSION["cryptKey"];
Link::$chave =  $_SESSION["cryptKey2"];

Arquivo: includes/funcoes.php

// Essa função irá retornar valores de $_POST['var'] ou $_PAR['$var']
function p($v){
	global $_POST, $_PAR;
	return isset($_POST[$v]) ? $_POST[$v] : (isset($_PAR[$v]) ? $_PAR[$v] : '');
}

Arquivo: includes/inicio.php

// Definimos o charset e inicializamos a session
header('Content-type: text/html; charset=UTF-8');
@session_start();
 
// incluímos as classes e os outros arquivos
include "funcoes.php";
include "classes/link.php";
include "config.php";
 
// agora tratamos a URL atual
Link::trataQuery();

Ufs. finalmente chegou a hora, vamos botar o sistema de Links para funcionar e vamos brincar com ele um pouco. vamos criar o arquivo /index.php

Exemplo de Link:
 
<a href="&lt;? echo Link::criaLink('') ?&gt;">Página inicial</a>
 
<a href="&lt;? echo Link::criaLink('usuarios.php', 'id=10') ?&gt;">Exemplo 1</a>
 
<a href="&lt;? echo Link::criaLink('principal.php') ?&gt;">Exemplo 2</a>
 
<a href="&lt;? echo Link::criaLink('noticia.php', 'id=10&amp;tipo=ultima&amp;skin=azul') ?&gt;">Exemplo 3</a>
 
Parabéns, a página  foi passada
<h2>Página Inicial</h2>
Nenhuma página passada, ou alguem tentou mudar a URL
 
Resultados:
 
<strong>Página:</strong>
 
<strong>Parametros:</strong>

Bom, é isso. espero que tenha sido bem explicado um exemplo funcional e arquivo para download está aqui: http://ferrari.eti.br/exemplos/fw1

Advertisement

25 comments

  1. jean disse:

    Carlos tenho uma duvida.

    Quero deixas testa função
    define (“rootfisico”, “/home/revistapratica/public_html/”);
    // Pasta do framework no servidor
    define (“rootvirtual”, “/seguranca/”);

    O root esta na pasta raiz seguranca.
    Quero chamar esta sua funcção em uma pasta acima chamada admclientes.
    Da objeto não encontrado
    admclientes/rootvirtual?A1skDEhJHB9aQ1oYH

    não estou me localizando nos links.

    obrigado

  2. Carlos André Ferrari disse:

    Jean,

    Este erro é porque no arquivo que está na past acima não tem a constante rootvirtual definida…

    te aconselho a mudar no seu php.ini a exibição padrao de erros de E_ALL ~ E_NOTICE para:
    error_reporting = E_ALL

    assim fica mais facil identificar esse tipo de problemas.

    []‘s

  3. Allyx disse:

    Tenho uma dúvida, gostaria de utilizar isto realmente para esconder a URL original, por exemplo:

    htttp://www.exemplo.com/base64/?XxNNClpgYAUGaVkGFi49DXVsFUZUDAY6DlYUFgMmX1kWFQZQXhsUeG4Waj5FFAYhb1h1OFhHURsGNkEEUERSYRRrQR8XUxdMQnhmBRJlBQYf

    Ao acessar este link, de fato visualizasse a página encriptada e não do modo que está atualmente no exemplo citado, já pesquisei e tentei personalizar porém não obtive sucesso.

  4. Carlos André Ferrari disse:

    Me manda seu codigo que eu tento entender o seu problema, assim por cima é complicado carlos[arroba]ferrari[ponto]eti[ponto]br

  5. André Caldas disse:

    Oi, Carlos!

    Vale lembrar que essa solução é mera obscuridade. Não deve ser tomada como solução de segurança. Já ouvi dizer que tem gente que põe código SQL na URL, por exemplo!!

    Uma solução melhor, se você realmente não quiser que a URL seja alterada (eu não vejo porque fazer isso), é algo do tipo:
    $url = $url + ‘url_md5=’ + md5sum( $url + $password )

    Aí você verifica o $url_md5. O mesmo vale para cookies… Se não bater é por que foi alterado. Só que usar a variável de sessão é melhor. Com a variável de sessão, isso tudo é transparente.

    Abraços,
    André Caldas.

  6. Carlos André Ferrari disse:

    é Obscuro, porém com uma chave randomica para encriptar (fraca, porém muda a cada session), e ainda tem o checksum que você citou como exemplo ai… então fica 99% eficiente, pois o invasor tem o timeout da session para descobrir a chave, a formula de checksum e possiveis salts usados na geração, depois tem que mudar e alterar tudo denovo…

  7. André Caldas disse:

    Oi, Carlos!

    Eu não havia reparado que o seu esquema na verdade possui duas etapas.
    1. É calculado um “hash” que verifica a integridade do query todo.
    2. É calculada uma chave para o XOR para criptografar a URL.

    Eu estava me referindo apenas à segunda etapa. A segunda etapa é meramente obscuridade. É bastante fácil de quebrar. O que é “seguro” aqui é o passo 2, o “checksum”. Que é na verdade o que eu estava sugerindo no primeiro post, sem ter atentado para o fato de que você já tinha feito. Desculpe pelo mal entendido.

    De qualquer forma, queria ainda sugerir umas coisas:
    * Não economize com substr(crypt(json_encode($p), Link::$chave), 0, 5).
    ** Utilize: crypt(json_encode($p), Link::$chave).
    ** Justificativa: é difícil embasar a decisão “cinco é suficiente” com algum argumento científico…

    * Não utilize uniqid() quando o que você quer é um valor aleatório (difícil de prever).
    ** uniqid() é para quando você quer um valor único, mas não necessariamente difícil de prever! Não é isso o que você quer. O uniqid() é fácil de prever. Se o sistema em algum outro momento deixar o usuário saber o valor de um uniqid(), os outros serão muito parecidos e portanto fáceis de prever.
    ** O login (id) é único. A senha não precisa ser única! ;-)

    * A menos que seja uma “one time key”, nunca use XOR pra criptografar nada.
    ** Sei que esse post é didático. :-)
    ** O problema é que se K é a chave, e você sabe A e B, então A xor K = B —> B xor A = K!! Demonstre. ;-)

    No mais, seu código (não só esse) é muito bom. :-)

    Continue firme, e parabéns pelo blog,
    André Caldas.

  8. André Caldas disse:

    Oops… correção: o que é seguro é o passo 1.

  9. marlon fonseca de oliveira disse:

    como eu faço para descriptografar a url, tipo ela voltar a ser “arquivo.php”? na hora de dar manutenção ao site ?

    antonio

  10. fredy disse:

    Amigo dá pra colocar o link http://ferrari.eti.br/exemplos/fw1 no ar para eu poder ver o funcionamento, fiz tudo aq mas nao deu certo. Abçs

  11. O link para download está quebrado poderia consertar ou mandar para o email phpdesenvolve@gmail.com tentei fazer passo a passo como descrito mas não obtive sucesso, se for possível desde já agradeço!

  12. Boa tarde Carlos.

    Tudo bem? cara, grande ideia essa que você. Parabéns.
    Preciso de um código bem semelhante ao seu só que modificado para wordpress.
    Me parece q

  13. Boa tarde Carlos.
    Tudo bem? cara, grande ideia essa que você. Parabéns.
    Preciso de um código bem semelhante ao seu só que modificado para wordpress.
    Eu estou começando em PHP, mas parece q o wordpress não aceita declaração de classes com ::
    Como ficaria teu código para funcionar em WordPress?

    Agradeço a atenção dispensada.

  14. Jeff disse:

    Kentucky Indiana Web Group handles Louisville web design, web graphic design, SEO,
    search engine optimization, web hosting, custom web programming,
    web hosting.

  15. whoah this blog is great i love reading your posts.
    Keep up the good work! You know, lots of individuals are looking
    round for this info, you could aid them greatly.

  16. I’d like to thank you for the efforts you have put in penning this site.

    I am hoping to view the same high-grade blog posts from you later
    on as well. In truth, your creative writing abilities has
    encouraged me to get my very own website now ;)

  17. Helpful info. Lucky me I found your site accidentally, and I’m shocked why this twist of fate didn’t came about in advance! I bookmarked it.

  18. Nam tinh disse:

    Magnificent beat ! I wish to apprentice whilst you amend your web site, how can i subscribe
    for a blog web site? The account helped me a
    applicable deal. I have been tiny bit acquainted of this your broadcast offered shiny transparent idea

  19. Ecka disse:

    Hey your tuiatrols are great..Are you going to do any other tuiatrols besides forums? I would like 1 where users can chat like a chat room.I tried going through the tuiatrols and always something comes up while I am doing it, can you post the full source for all the files please?

Deixe uma resposta