segunda-feira, 7 de junho de 2010

Tipo ENUM no MySQL e no PostgreSQL

Tempos atrás eu publiquei aqui, sobre os tipos ENUM e SET no MySQL, porém as respostas dos leitores deixaram claro que eu não havia explicado o assunto direito. E relendo o texto, realmente assumo que ficou péssimo. Não consegui passar o conceito, quanto menos a aplicabilidade desses recursos.

Então aqui cabe a redenção. Vamos ao tipo ENUM. Ele não é um tipo definido no padrão SQL, e sim implementações proprietárias, encontrado nos bancos de dados mais comuns. Assim seu comportamento, espaço em disco e queries que podem ser usadas diferem ligeiramente entre suas implementações, mas a idéia por trás do tipo ENUM é comum a todos.

As vantagens do uso do tipo ENUM são:
  • ganho de performance
  • segurança dos dados

As desvantagens são:
  • limites de uso (a alteração requer a reestruturação da tabela)
  • a não portabilidade devido as diferenças de implementação

A principal característica do tipo ENUM é permitir a criação de uma lista enumerada, sendo cada registro um par index-value. A idéia é bem simples mesmo, mas extremamente eficaz e poderosa. O uso do tipo ENUM deve ser feito em parâmetros onde há pouca ou nenhuma alteração durante a existência da aplicação - por exemplo, sexo, ou um sistema de rating com valores fixos de entrada.

CREATE TABLE 'myPics' (
'id' INT NOT NULL AUTO_INCREMENT ,
'url' VARCHAR( 255 ) NOT NULL ,
'rate' ENUM('bad', 'good', 'excellent') NULL DEFAULT 'good',
PRIMARY KEY ('id') ,
INDEX ('url')
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

Na tabela de exemplo acima, criamos o campo rate, que deve armazenar a classificação da foto. Os possíveis valores são: NULL, 'bad', 'good' e 'excellent'. Ou seja você tem valores pré-definidos para o input de dados, e a cada um é atribuído um índice na ordem em que foram declarados. Os possíveis valores para o nosso campo são:
valor índice
NULL NULL
'' 0
bad 1
good 2
excellent 3

Na hora da query uma possível construção seria:

SELECT name, rate FROM myPics WHERE rate >= 'good';

Isso demonstra a utilidade do tipo ENUM. Ao invés de criar uma tabela auxiliar e atribuir valores a ela, podemos reduzir essa complexidade fazendo uso do tipo ENUM em nossa arquitetura. Ah sim, qualquer função que demande tipos numéricos (SUM(), AVG(), MIN(), MAX(), COUNT()....) podem ser usadas em cima dos campos ENUM. Nesse caso, os valores são primeiro transformados no seu índice numérico.

E vale mencionar mais uma vez que o índice atribuído depende da ordem da declaração dos possíveis valores. Se você declarar ENUM ('bom', 'ruim'), 'bom' terá um valor menor do que 'ruim', e se declarar ENUM ('ruim', 'bom'), 'ruim' terá um valor menor do que 'bom'.

No Postgresql o uso do tipo enum é ligeiramente diferente. O trecho a seguir ilustra o mesmo exemplo anterior, só no que postgre.

CREATE TYPE rating AS ENUM ('bad', 'good', 'excellent');
CREATE TABLE myPics (
id serial,
url varchar(255),
rate rating
);

É necessário criar um tipo de dado com nome próprio do tipo ENUM, e depois atribuí-lo à coluna. Na hora de utilizar, nos beneficiamos dos mesmos recursos de construção.

Agora sobre o tipo SET. O tipo SET só existe no MySQL. E uma possível aplicação para ilustrar sua utilidade seria um sistema de tags, implementado de forma nativa na tabela.

Considere a seguinte tabela:

CREATE TABLE 'myPics' (
'id' INT NOT NULL AUTO_INCREMENT ,
'url' VARCHAR( 255 ) NOT NULL ,
'rate' ENUM('bad', 'good', 'excellent') NULL,
'tags' SET('outdoor', 'studio', 'stock', 'fruits', 'nature', 'close-up', 'people') NULL
PRIMARY KEY ('id') ,
INDEX ('url')
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin

Nela, podemos atribuir valores como:

INSERT INTO myPics (id, url, rate, tags) VALUES (NULL, 'xxx', 'good', 'people, close-up'), (NULL, 'yyy', 'excellent', 'fruits, nature, close-up');

Ou seja declarando as tags direto no insert. Na hora de fazer o SELECT, contamos com mais uma função nativa do MySQL bem útil, a FIND_IN_SET:

SELECT * from myPics WHERE FIND_IN_SET('nature', tags) > 0 AND FIND_IN_SET('close-up', tags) > 0;

Isso vai trazer todos os registros cujo campo tags contenha os valores 'nature' e 'close-up'.

Bom, acho que agora o conceito e a aplicação dos tipos ENUM e SET está agora mais clara e mais útil.

-----------
keepReading

quarta-feira, 2 de junho de 2010

Open Source e o bug tracking

Fala pessoal,

nem preciso dizer que sou um entusiasta do movimento do software livre. Embora existam algumas divergências e tecnicismos sobre as definições e terminologias sobre o que é open source, o que é livre e etc... uma coisa é certa: o espírito de ajuda mútua em criar algo que beneficie quem usa os softwares.

E isso é feito de várias formas. Uma das bases desse mundo é a relatação de defeitos encontrados. É algo simples, eficaz e que muitas empresas privadas de desenvolvimento de software adotaram. Você está usando o programa e de repente ele trava, ou dá uma mensagem de erro. Bem, você então relata este erro aos desenvolvedores, assim eles podem investigar o que aconteceu, e trabalhar para a melhoria do produto. Desta forma todo mundo ganha.

Mas se tem algo que me deixa puto da vida é quando eu tenho um bug para reportar, depois de muita googlada, pesquisa, etc, e o serviço de bug tracking não responde de acordo, ou torna a tarefa de reportar um bug mis complicada do que deveria. É o que está acontecendo comigo neste exato momento.

Eu concordo que se deva oferecer ferramentas que automatizem a tarefa de juntar informações necessárias, ainda mais com usuários menos experientes, assim eles podem dar uma contribuição de qualidade, mesmo sem enteder muito do sistema.

Mas no caso eu poderia reportar um bug, com muita informação, e simplesmente não consigo. Processo complicado demais, lento demais, e instável demais (timeouts, internal errors..).

Fico chateado de ver isso, sinceramente. Pois é um gargalo a mais na hora de melhorar a qualidade do produto. E assim a comunidade se enfraquece.

----------- keepReading

A Verdade sobre Sessões

Estou iniciando uma série aqui no blog. Vou traduzir artigos e posts renomados sobre programação e desenvolvimento.

Para a estréia, escolhi um artigo altamente esclarecedor do Chris Shiflett, The Truth About Sessions, que explica em detalhes como as seções do PHP funcionam. Este artigo está originalmente sob licensa Creative Commons, bem como esta tradução. Vamos lá.

Introdução

Praticamente toda aplicação em PHP usa sessões. Este artigo dá uma olhada detalhada na implementação de um mecanismo seguro de gerência de sessões em PHP. Seguindo uma introdução básica de HTTP, o desafio de manter estado, e a operação básica de Cookies, eu vou explicar através de métodos simples e efetivos que podem ser usados para aumentar a segurança e a confiabilidade de suas aplicações PHP com estado.

A falta de estado

HTTP é um protocolo sem estado. Isso porque não há nada dentro do protocolo que requisite que o browser identifique a si mesmo em cada requisição, e também não há nenhuma conexão estabelecida entre o browser e o servidor que persista entre uma página e a próxima. Quando um usuário visita um site, o browser do usuário envia uma requisição HTTP ao servidor, que por sua vez envia uma resposta HTTP de volta. Essa é a extensão da comunicação, e representa uma transação HTTP completa.

Como a web se baseia em comunicações HTTP, manter o estado em aplicações web pode ser particularmente desafiador para desenvolvedores. Cookies são uma extensão do HTTP que foram introduzidos para ajudar a providenciar transações HTTP com estado, mas preocupações com privacidade levaram muitos usuários a desabilitar o suporte a cookies. Informações sobre estado podem ser passadas na URL, mas a divulgação acidental dessa informação mostra sérios riscos de segurança. De fato, a própria natureza de manter estado requer que o cliente identifique a si mesmo, assim a nossa consciência sobre segurança nos diz que nós nunca devemos confiar nas informações enviadas pelos clientes.

Apesar de tudo isso, existem soluções elegantes para o problema de manter o estado. Não existe solução perfeita, é claro, nem existe uma única solução que satisfaça as necessidades de todos. Este artigo introduz algumas técnicas que podem confiavelmente prover o manutenção do estado, bem como se proteger contra técnicas de invasão através de ataques de sessão, como o roubo de sessão. Mais abaixo, você vai aprender como os cookies realmente funcionam, o que as seções PHP fazem, e o que é preciso para roubar uma sessão.

Visão geral sobre HTTP

Para apreciar o desafio de manter o estado bem como escolher a melhor solução às suas necessidades, é importante entender um pouco sobre a arquitetura de web por trás disso tudo, o HyperText Transfer Protocol (HTTP).

Uma visita a http://exemplo.org/ requer que o navegador envie uma requisição HTTP para exemplo.org na porta 80. A sintaze dessa requisição é algo mais ou menos assim:
GET / HTTP/1.1
Host: exemplo.org

A primeira linha é chamada linha de requisição, e o segundo parâmetro (uma barra neste exemplo) é o caminho do recurso solicitado. Uma barra representa a raíz do documento; o servidor web transforma a raíz do documento para um caminmho específico no sistema de arquivos. Usuários do Apache podem estar acostumados a configurar este caminho com a diretiva DocumentRoot. Se http://www.exemplo.org/caminho/para/script.php é solicitado, o caminho para o recurso solicitado na requisição é /caminho/para/script.php. Se a raíz do documento está definida para ser /usr/local/apache/htdocs, o caminho completo para o recurso que o servidor irá usar é /usr/local/apache/htdocs/caminho/para/script.php

Existem muitas tecnologias como mod_rewrite que oferecem mais flexibilidade quando estão mapeando uma URL para um recurso específico

A segunda linha ilustra a sintaxe de de um cabeçalho HTTP. O cabeçalho neste exemplo é Host, e identifica o nome do domínio do servidor onde o browser pretende requisitar um recurso. Este cabeçalho é requerido pelo HTTP/1.1 e ajuda a prover suporte a mecanismos de virtual hosting, múltiplos domínios sendo servidor por um único endereço IP público. Existem muitos outros cabeçalhos opcionais que podem ser incluídos numa requisição, e você pode estar familiarizado em fazer referência a alguns deles no seu código PHP; exemplos incluem $_SERVER['HTTP_REFERER'] que se refere ao cabeçalho Referer e $_SERVER['HTTP_USER_AGENT'] que se refere ao cabeçalho User-Agent.

Uma nota particular desta requisição é que não há nada dentro dela que possa ser usado para identificar unicamente para identificar o cliente. Alguns desenvolvedores recorrem a informações obtidas do do TCP/IP (como o endereço IP) para identificação única, mas essa abordagem tem muitos problemas. Mais notavelmente, um único usuário pode potencialmente usar diferentes endereços IP para cada requisição (como no caso de grandes provedores de internet como AOL), e vários usuários podem usar o mesmo endereço IP (como no caso de laboratórios de computador usando um proxy HTTP). Estas situações podem fazer com que um único usuário aparente ser vários, ou muitos usuários aparentar ser apenas um. Para qualquer método de prover estado seguro e confiável, apenas informações obtidas do HTTP podem ser usadas.

O primeiro passo em manter o estado da aplicação é de alguma forma identificar unicamente cada cliente. Visto que a única fonte confiável de informações que podem ser usadas para a identificação deve vir da requisição HTTP, é necessário algo esteja dentro da requisição que possa ser usado para identificação única. Existem algumas poucas formas de se fazer isso, mas a solução desenvolvida para resolver este problema em particular é o cookie.

Cookies

A constatação de que deve haver um método único de identificação dos clientes resultou nos cookies, uma solução bastante criativa. Cookies são mais fáceis de entender se você considerá-los uma extensão do protocolo HTTP, o que é precisamente o que eles são. Os cookies estão definidos pelo RFC 2965, embora a especificação original escrita pela Netscape se aproxime mais do suporte à indústria.

Existem dois cabeçalhos HTTP que são necessários para se implementar os cookies, Set-Cookie e Cookie. O servidor web inclui o cabeçalho Set-Cookie em resposta a uma requisição para que o browser inclua este cookie em futuras requisições. Um navegador compatível que está com os cookies ativados inclui o cabeçalho Cookie em todas as requisições subsequentes (que satisfaçam as condições definidas pelo cabeçalho Set-Cookie) até que o cookie expire. Um scenario típico consiste de duas transações (quatro mensagens HTTP):

  1. O cliente envia uma requisição HTTP
  2. O servidor envia uma resposta HTTP que inclui o cabeçalho Set-Cookie
  3. O cliente envia uma requisição com o cabeçalho Cookie
  4. O servidoe envia uma resposta HTTP

Esta troca está ilustrada na figura 1:

Figura 1

A adição do cabeçalho Cookie na segunda requisição do cliente providencia a informação que o servidor pode usar para identificar unicamente o cliente. Também é neste ponto que o servidor (ou um script PHP no lado do servidor) pode determinar se o usuário tem cookies habilitados. Embora o usuário possa escolher desabilitar os cookies, é razoavelmente seguro assumir que as preferências do usuário não vão mudar enquanto ele interage com sua aplicação. Este fato pode provar ser muito útil, como em breve será demonstrado.

Dados GET e POST

Existem dois métodos adicionais que um cliente pode usar para enviar dados ao servidor, e estes métodos são anteriores aos cookies. Um cliente pode incluir informação na URL requisitada, tanto na query string ou como parte do caminho. Como um exemplo de query string, considere a seguinte requisição:
GET /index.php?foo=bar HTTP/1.1
Host: example.org
O script receptor, index.php, pode referenciar $_GET['foo'] para fazer referência ao valor bar. Por isso, muitos desenvolvedores PHP se referenciam a estes dados como dados GET (outros algumas vezes chamam de dados query string, ou variáveis de URL). Um ponto de confusão comum, é que os dados GET podem existir mesmo numa requisição POST, porque eles são simplesmente parte da URL e não dependem do método de requisição.

Uma outra forma que os os clientes pode usar para enviar dados é utilizando a porção conteúdo da requisição HTTP. Esta técnica requer que o método de requisição seja o POST, e um exemplo de tal requisição é como o seguinte:
POST /index.php HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

Neste caso, o script receptor, index.php, pode se referenciar a $_POST['foo'] para fazer referência ao valor bar. Os desenvolvedores PHP se referem tipicamente a estes dados como dados POST, e é assim que um browser passa os dados submetidos através de um formulário cuja propriedade method é o POST.

Um request pode potencialmente ter os dois tipos de dado, desta forma:
POST /index.php?myget=foo HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

mypost=bar

Estes dois métodos adicionais de enviar dados podem prover substitutos aos cookies. Diferente dos cookies, GET e POST não são opcionais, então estes métodos são mais confiáveis. Considere um identificador único chamado PHPSESSID incluído na URL requerida como segue:
GET /index.php?PHPSESSID=12345 HTTP/1.1
Host: example.org

Isto cumpre com o mesmo objetivo do cabeçalho Cookies, porque o cliente identifica a si mesmo, mas é muito menos automático para o desenvolvedor. Uma vez que o cookie está definido, é responsabilidade do browser enviá-lo nas requisições subsequentes. Para propagar o identificador único através das URLs, o desenvolvedor precisa garantir que todos os links, formulários, e similares a ter a query string apropriada (o PHP pode ajudar nisso se você habilitar a opção session.enable_trans_sid). Em adição, dados GET são mostrados na URL e são muitos mais expostos do que cookies. De fato, usuários desavisados podem salvar tais URLs nos favoritos, enviar para um amigo, ou um número qualquer de outras coisas que podem acidentalmente revelar sua identificação única.

Embora os dados POST sejam menos suscetíveis a serem expostos, propagar o identificador único como uma variável POST requer que todas as requisições ao servidor sejam também POST. Esta não é uma opção conveniente, ainda que o design da sua aplicação possa fazer isso viável.

Gerenciamento de sessões

Até agora, eu discuti sobre estado. Este é um detalhe de nível baixo o bastante que envolve o a associação de uma transação HTTP com outra. O recurso mais útil com o qual provavelmente você esteja familiarizado seja o gerenciamento de sessões. Gerenciamento de sessões não se baseia apenas na habilidade de manter o estado, mas também requer que você mantenha dados unicamente associados com cada usuário. Este dados costumam ser chamados de dados de seção, porque são associados com uma seção específica do usuário. Se você usa o mecanismo nativo do PHP para gerenciamento de sessões, os dados de sessão são mantidos para você (em /tmp por padrão) e disponíveis através do vetor superglobal $_SESSION. Um exemplo simples do uso de sessões envolve a persistência dos dados de sessão entre uma página e a próxima. A lista 1, start.php, demonstra como isso pode ser feito:

Lista 1:
<?php

session_start();
$_SESSION['foo'] = 'bar';

?>

<a href="continue.php">continue.php</a>

Assumindo que o usuário clica no link dentro de tart.php, o script receptor (continue.php) poderá acessar a mesma variável de sessão, $_SESSION['foo']. Isto é mostrado na lista 2.

Lista 2:
<?php
session_start();
echo $_SESSION['foo']; /* bar */
?>

Sérios riscos existem quando você escreve o código desta forma sem entender o que o PHP faz por você. Sem este conhecimento, você poderá achar difícil depurar erros de sessões, ou prover um nível razoável de segurança.

Personificação

É um equívoco comum acreditar que o mecanismo de gerenciamento de sessões nativo do PHP provê defesas contra os ataques baseados em sessões. Ao contrário, o PHP simplesmente provê um mecanismo conveniente. É responsabilidade do desenvolvedor prover as defesas de segurança apropriadas. Como mencionado antes, não existe solução perfeita, nem uma melhor solução apropriada que se aplique a todos.

Para explicar o risco da personificação, considere a seguinte série de eventos:

  1. Pessoa inocente visita http://www.exemplo.org/ e faz login
  2. exemplo.org define um cookie, PHPSESSID=12345
  3. Pessoa maliciosa visita http://www.exemplo.org/ e apresenta um cookie, PHPSESSID=12345
  4. exemplo.org confunde pessoa maliciosa com pessoa inocente

Estes eventos estão ilustrados na figura 2.

Figura 2


É claro, este cenário assume que a pessoa maliciosa de alguma forma descobre ou adivinha a PHPSESSID válida que pertence a pessoa inocente. Enquanto isto pode parecer improvável, é um exemplo de segurança sobre obscuridade e não é algo sobre o qual devemos nos basear. Obscuridade não é uma coisa ruim, é claro, e pode ajudar, mas precisa ser algo mais substancial no lugar que ofereça proteção confiável contra tais ataques.

Prevenindo a personificação

Existem muitas técnicas que podem ser usadas para complicar a personificação ou outros ataques baseados em sessões. A aproximação geral, é fazer as coisas tão convenientes quanto for possível para legitimar seus usuários e tão complicadas quanto possível para os atacantes. Este é um balanço desafiante a ser atingido, e o balanço perfeito depende muito do design da aplicação. Assim, você é o melhor juiz no fim das contas.

A requisição HTTP/1.1 válida mais simples consiste de uma linha de requisição e o cabeçalho Host.

GET / HTTP/1.1
Host: example.org

Se o cliente estiver passando o identificador único de sessão PHPSESSID, este pode ser passado no cabeçalho Cookie como a seguir:

GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345

Alternativamente, o cliente pode passar o identificador único de sessão na URL requisitada

GET /?PHPSESSID=12345 HTTP/1.1
Host: example.org

O identificador de sessão também pode ser incluído como dados POST, mas isto tipicamente envolve uma experiência de usuário menos amigável e é a abordagem menos popular.

Porque a informação obtida do TCP/IP não pode ser confiavelmente usada para ajudar a fortalecer a segurança do mecanismo, parece que há pouco o que um desenvolvedor pode fazer para complicar a personificação. Apesar de tudo, a única coisa que um atacante precisa fazer é enviar o mesmo identificador único que um usuário legítimo enviaria para personificar aquele usuário e roubar a sessão. Assim, parece que a única proteção é manter o identificador de sessão oculto ou fazer com que ele seja mais difícil de adivinhar (preferencialmente ambos).

O PHP gera um identificador de sessão randômico, que é praticamente impossível de adivinhar, então esta preocupação já está mitigada. Prevenir um atacante de descobrir um identificador válido de sessão é muito mais difícil, porque muito dessa responsabilidade está fora do domínio onde o desenvolvedor tem controle.

Existem muitas situações que podem resultar na exposição do identificador de sessão do usuário. Dados GET podem ser erroneamente guardados em cache, observados por um estranho, guardado nos favoritos, ou enviados por email. Cookies provêm um mecanismo mais safo, mas usuários podem desabilitar o suporte a cookies, descartando a possibilidade de usá-los, e vulnerabilidades passadas no Internet Explorer foram conhecidas por revelar cookies a sites não autorizados.

Assim, um desenvolvedor pode estar bem certo de que o identificador de sessão não possa ser adivinhado, mas a possibilidade de que ele seja revelado a um atacante é mais provável, independente do método utilizado para propagá-lo. Algo adicional é necessário para ajudar a prevenir a personificação.

Na prática, uma típica requisição HTTP inclui muitos cabeçalhos opcionais além do Host. Por exemplo, considere a seguinte requisição:

GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1
Accept: text/html;q=0.9, */*;q=0.1
Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66
Accept-Language: en

Este exemplo inclui quatro cabeçalhos opcionais, User-Agent, Accept, Accept-Charset, e Accept-Language. Como estes cabeçalhos são opcionais, não é muito inteligente contar com sua presença. Contudo, se o browser de um usuário envia estes cabeçalhos, é seguro assumir que eles estarão presentes nas requisições subsequentes? A resposta é sim, com poucas exceções. Assumindo o exemplo anterior como sendo uma requisição enviada de um usuário atual com uma sessão ativa, considere a seguinte requisição subsequente enviada pouco depois:

GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345
User-Agent: Mozilla/5.0 (compatible; IE 6.0 Microsoft Windows XP)

Como o mesmo identificador único está sendo apresentado, a mesma sessão PHP será acessada. Se o browser está identificando a si mesmo de forma diferente do que na interações anteriores, nós devemos assumir que é o mesmo usuário?

Está claro que isto não é desejável, mas é exatamente isto o que acontece se você não escreveum código que especificamente não checa situações assim. Mesmo nos casos onde você não consegue ter certeza que a requisição é um ataque de personificação, simplesmente pedir que a senha ao usuário pode ajudar a prevenir a personificação sem afetar demais os uauários adversamente. Isto é um ponto importante.

Você pode adicionar a validação do User-Agent ao seu modelo de segurança de forma similar à lista 3.

Lista 3:

<?php
session_start();

if (md5($_SERVER['HTTP_USER_AGENT']) != $_SESSION['HTTP_USER_AGENT']) {
/* Prompt for Password */
exit;
}

/* Rest of Code */
?>

É claro, primeiro você precisará armazenar o digest MD5 do user agent que iniciou a sessão, como mostrado na lista 4.

Lista 4:

<?php
session_start();

$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
?>

Enquanto não é necessário que você o MD5 do User-Agent, isso ajuda a providenciar consistência e elimina a necessidade de filtrar $_SERVER['HTTP_USAR_AGENT'] antes de usá-la. Como essa informação é originada de uma fonte remota, não podemos confiar de forma cega nela, mas o formato de um digest MD5 é consistente.

Agora que você exige a consistência de User-Agent, um atacante deve cumprir dois passos para roubar a sessão:

  1. Capturar um identificador de sessão válido.
  2. Apresentar o User-Agent da vítima na tentativa de personificação.

Enquanto isto é claramento possível, é ligeiramente mais complicado, e desta forma o mecanismo de sessão já está mais seguro.

Outros cabeçalhos podem ser adicionados desta forma, e você pode até mesmo usar uma combinação de cabeçalhos como uma impressão digital. Se você também incluir algum tipo de revestimento de algum tipo, esta impressão digital se torna praticamente impossível de adivinhar. Considere o exemplo da lista 5.

Lista 5:

<?php

session_start();

$fingerprint = 'SHIFLETT' . $_SERVER['HTTP_USER_AGENT'];
$_SESSION['fingerprint'] = md5($fingerprint . session_id());

?>

O cabeçalho Accept não deve ser usado nesta impressão, porque alguns browsers podem variar o valor deste cabeçalho quando o usuário atualiza a página.

Com uma impressão digital que é difícil de adivinhar, pouco é ganho não usando-a. Considere um mecanismo de sessão onde a impressão digital é propagada como o identificador de sessão. Nesta caso, um atacante deve completar os três passos seguintes para roubar uma sessão com sucesso:

  1. Capturar um identificador de sessão válido.
  2. Apresentar os mesmo cabeçalhos HTTP usados para gerar a impressão.
  3. Apresentar a impressão digital da vítima.

Se ambos o identificador de sessão e a impressão digital são propagadas como dados GET, ainda é possível que um atacante que obtenha um também consiga ter acesso ao outro. Uma abordagem mais segura é utilizar dois métodos diferentes de propagação, dados GET e cookies. É claro, isto depende das preferências do usuário, mas um nível extra de proteção pode ser oferecido para aqueles que habilitam os cookies. Assim, se um atacante obtém um identificador único por uma vulnerabilidade do browser, a impressão digital ainda continua desconhecida.

Existem muitos outros mecanismos que podem ser usados para ajudar a fortalecer a segurança do seu mecanismo de sessões. Esperamos que você esteja no caminho de criar as suas próprias técnicas. Afinal, você é o expert das suas próprias aplicações, então munido com um bom entendimento de sessões, você é a melhor pessoa para implementar alguma segurança adicional.

Obscuridade


Eu gostaria de desfazer um mito sobre a obscuridade. O mito é de que "não existe segurança através da obscuridade". Como mencionei antes, obscuridade não é algo que oferece a proteção adequada, nem deve ser tomada por base. Contudo, isso não significa que não há absolutamente nada a ser ganhar. Resguardado por um mecanismo seguro de sessões, obscuridade pode oferecer um pouco de segurança adicional.

O simples uso de nomes de variáveis que induzam ao erro para o identificador de sessão e para a impressão digital já ajudam. Você também pode propagar dados de engodo para confundir um potencial atacante. Estas técnicas certamente não devem ser usadas como a base para proteção, é claro, mas você não irá perder seu tempo implementando um pouquinho de obscuridade no seu próprio mecanismo.

Sumário


Eu espero que você tenha ganho diversas coisas deste artigo. Notavelmente, agora você deve ter um entendimento básico de como a web funciona, de como o estado completo é alcançado, o que é realmente um cookie, como as sessões do PHP funcionam, e algumas técnicas que você pode usar para aumentar a segurança das suas sessões.

Se você gostou deste artigo, você pode estar interessado em outros:


Se você desenvolver um mecanismo de sessões seguro por conta própria, por favor, sinta-se à vontade para compartilhar com a comunidade. Eu adoraria ouvir sobre suas próprias soluções, e eu espero que este artigo tenha fornecido as informações de base necessárias para dar suporte à sua própria criatividade.

----------- keepReading