Qual é a melhor maneira de impedir o seqüestro de sessões?

124

Especificamente, isso se refere ao uso de um cookie de sessão do cliente para identificar uma sessão no servidor.

É a melhor resposta para usar a criptografia SSL / HTTPS em todo o site e você tem a melhor garantia de que nenhum homem no meio dos ataques poderá detectar um cookie de sessão do cliente existente?

E talvez o segundo melhor usar algum tipo de criptografia no próprio valor da sessão que é armazenado no seu cookie de sessão?

Se um usuário mal-intencionado tiver acesso físico a uma máquina, ele ainda poderá consultar o sistema de arquivos para recuperar um cookie de sessão válido e usá-lo para seqüestrar uma sessão?

Adão
fonte

Respostas:

140

Criptografar o valor da sessão terá efeito zero. O cookie da sessão já é um valor arbitrário, criptografando apenas gera outro valor arbitrário que pode ser detectado.

A única solução real é HTTPS. Se você não deseja fazer SSL em todo o site (talvez tenha problemas de desempenho), poderá conseguir apenas SSL protegendo as áreas sensíveis. Para fazer isso, primeiro verifique se sua página de login é HTTPS. Quando um usuário faz login, defina um cookie seguro (ou seja, o navegador o transmitirá apenas por um link SSL), além do cookie de sessão normal. Em seguida, quando um usuário visitar uma de suas áreas "sensíveis", redirecione-as para HTTPS e verifique a presença desse cookie seguro. Um usuário real terá, um seqüestrador de sessão não.

EDIT : Esta resposta foi originalmente escrita em 2008. Agora é 2016 e não há razão para não ter SSL em todo o site. Chega de HTTP em texto sem formatação!

Josh Hinman
fonte
28
HTTPS impedirá apenas o sniffing. Mas se você possui um XSS, ou os IDs de sessão podem ser adivinhados facilmente, ou você é vulnerável à fixação da sessão ou seu armazenamento de IDs de sessão é fraco (injeção de SQL?), O SSL não será uma melhoria.
Calimo
5
@ Josh Se um usuário mal-intencionado tiver acesso físico a uma máquina, ele ainda poderá consultar o sistema de arquivos para recuperar um cookie de sessão válido e usá-lo para seqüestrar uma sessão?
Pacerier
72
Se um usuário mal-intencionado tiver acesso físico a um sistema de arquivos, ele não precisará invadir uma sessão.
Josh Hinman
25
@ Josh. Não é verdade, às vezes um usuário tem acesso físico por tempo limitado a um sistema de arquivos. Imagine um laptop deixado desbloqueado por um colega correndo para o banheiro, agora tudo o que preciso fazer é ir ao laptop, instalar o plugin EditThisCookie, pegar os cookies em plus.google.com usando o recurso de exportação EditThisCookie e agora tenho a conta dele . Tempo necessário: 18 segundos.
Pacerier 13/10/12
1
Tenho certeza de que o Google vai ter algum tipo de recurso de segurança build-in como este é, obviamente, a primeira coisa que você pensa quando falar sobre o seqüestro de sessão
xorinzor
42

O SSL apenas ajuda nos ataques de sniffing. Se um invasor tiver acesso à sua máquina, assumirei que ele também pode copiar seu cookie seguro.

No mínimo, verifique se os cookies antigos perdem seu valor depois de um tempo. Mesmo um ataque hijaking bem-sucedido será frustrado quando o cookie parar de funcionar. Se o usuário tiver um cookie de uma sessão que efetuou login há mais de um mês, faça com que ele digite novamente sua senha. Certifique-se de que sempre que um usuário clicar no link "sair" do seu site, o UUID da sessão antiga nunca possa ser usado novamente.

Não tenho certeza se essa ideia vai funcionar, mas aqui vai: Adicione um número de série ao cookie da sessão, talvez uma string como esta:

SessionUUID, número de série, data / hora atuais

Criptografe essa sequência e use-a como seu cookie de sessão. Altere regularmente o número de série - talvez quando o cookie tiver 5 minutos e depois emita novamente o cookie. Você pode até reemitê-lo em todas as visualizações de página, se quiser. No lado do servidor, mantenha um registro do último número de série emitido para essa sessão. Se alguém alguma vez envia um cookie com o número de série errado, significa que um invasor pode estar usando um cookie que ele interceptou anteriormente, invalidando o UUID da sessão e solicitando ao usuário que digite novamente sua senha e emita novamente um novo cookie.

Lembre-se de que seu usuário pode ter mais de um computador e, portanto, mais de uma sessão ativa. Não faça algo que os force a fazer login novamente sempre que alternarem entre computadores.


fonte
Sei que essa é uma postagem antiga, mas só queria incluir que, se um invasor seqüestrar a sessão dentro da janela atribuída pelo "número de série", isso não o afetaria.
esmagar
@crush, mas o atacante seria trancado após a janela alocada, certo? Portanto, no mínimo, a janela de ataque é pequena (er).
11119 Johanneke
2
O único problema é se o usuário deixa o seu site por 5 minutos, eles vão ter que logar novamente
elipoultorak
21

Você já pensou em ler um livro sobre segurança PHP? Altamente recomendado.

Eu tive muito sucesso com o método a seguir para sites sem certificação SSL.

  1. Desabilite várias sessões na mesma conta, certificando-se de que você não está verificando isso apenas pelo endereço IP. Em vez disso, verifique pelo token gerado no login, que é armazenado com a sessão de usuários no banco de dados, assim como o endereço IP, HTTP_USER_AGENT e assim por diante.

  2. Usando hiperlinks baseados em relação Gera um link (por exemplo: http://example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8 ) O link é anexado com uma sequência MD5 salgada aleatória x-BYTE (tamanho preferido), após o redirecionamento da página, gerada aleatoriamente token corresponde a uma página solicitada.

    • Ao recarregar, várias verificações são feitas.
    • Endereço IP de origem
    • HTTP_USER_AGENT
    • Token de Sessão
    • você entendeu.
  3. Cookie de autenticação de sessão de curta duração. como postado acima, é uma boa idéia um cookie contendo uma string segura, que é uma das referências diretas à validade das sessões. Faça com que expire a cada x Minutos, reemitindo esse token e sincronizando novamente a sessão com os novos Dados. Se houver erros de correspondência nos dados, desconecte o usuário ou faça com que ele autentique novamente sua sessão.

Eu não sou um especialista no assunto, tenho um pouco de experiência neste tópico em particular, espero que isso ajude alguém por aí.

Nathan
fonte
4
Existem livros que você recomendaria?
Rikki
1
Especialmente considerando que o OP não especificou nada sobre o PHP especificamente, eu diria que é melhor examinar apenas um livro de segurança geral (especialmente porque a segurança entre linguagens diferentes difere apenas nos detalhes da implementação, mas os conceitos permanecem os mesmos).
matts1
em 2017, mesmo o facebook / gmail etc. permite várias sessões na mesma conta (especialmente com dispositivos móveis), a menos que você odeie seus usuários, o número 1 está um pouco desatualizado.
cowbert
20
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

O que isso faz é capturar informações 'contextuais' sobre a sessão do usuário, informações que não devem mudar durante a vida de uma única sessão. Um usuário não estará em um computador nos EUA e na China ao mesmo tempo, certo? Portanto, se o endereço IP mudar repentinamente na mesma sessão, o que implica fortemente em uma tentativa de seqüestro de sessão, você protege a sessão encerrando a sessão e forçando o usuário a se autenticar novamente. Isso frustra a tentativa de invasão, o invasor também é forçado a fazer login, em vez de obter acesso à sessão. Notifique o usuário sobre a tentativa (ajax um pouco), e vola, Usuário ligeiramente irritado + informado e sua sessão / informação está protegida.

Lançamos o User Agent e o X-FORWARDED-FOR para fazer o melhor para capturar a exclusividade de uma sessão para sistemas atrás de proxies / redes. Você pode usar mais informações do que isso, sinta-se à vontade para ser criativo.

Não é 100%, mas é bastante eficaz.

Você pode fazer mais para proteger as sessões, expirar quando um usuário sair de um site e voltar forçá-lo a fazer login novamente, talvez. Você pode detectar um usuário saindo e voltando capturando um HTTP_REFERER em branco (o domínio foi digitado na barra de URL) ou verifique se o valor no HTTP_REFERER é igual ao seu domínio ou não (o usuário clicou em um link externo / criado para acessar seu local).

Expirar sessões, não deixe que elas permaneçam válidas indefinidamente.

Não confie nos cookies, eles podem ser roubados, é um dos vetores de ataque para seqüestro de sessão.

theironyis
fonte
3
Eu já havia passado por uma situação em que um determinado ISP (razoavelmente grande, mas tecnicamente atrasado) alterava o IP do navegador do usuário de tempos em tempos, com base no roteamento das conexões dos usuários. Isso fez com que a verificação REMOTE_ADDR retornasse falsos negativos para nós.
usar o seguinte código
Por que se preocupar em criar um hash? $_SESSION['ident'] = $aip . $bip . $agent;seria tão seguro.
Dan Bray
2
Se você tiver usuários móveis usando seu site em movimento e mudando de um ponto de acesso para outro, os IPs deles continuarão sendo alterados e eles serão desconectados da conta.
Kareem
E os proxies e VPNs? Qualquer pessoa que use um proxy TOR será constantemente desconectada de suas contas ... a cada poucos minutos, de fato.
Bradley
Mesmo se você ignorar isso, os endereços IP podem ser manipulados pelo cliente, portanto isso não faria muito para dissuadir um invasor de qualquer maneira.
Bradley
9

Experimente o protocolo Secure Cookie descrito neste documento por Liu, Kovacs, Huang e Gouda:

Conforme declarado no documento:

Um protocolo de cookie seguro executado entre um cliente e um servidor precisa fornecer os quatro serviços a seguir: autenticação, confidencialidade, integridade e anti-replay.

Quanto à facilidade de implantação:

Em termos de eficiência, nosso protocolo não envolve nenhuma pesquisa de banco de dados ou criptografia de chave pública. Em termos de capacidade de implantação, nosso protocolo pode ser implantado facilmente em um servidor da Web existente e não requer nenhuma alteração na especificação de cookies da Internet.

Resumindo: é seguro, leve, funciona muito bem para mim.

Hubert
fonte
9
Seu link é uma especificação do protocolo - você tem um link para uma implementação? Isso seria ótimo, obrigado.
Adam
9

Não há como impedir que a sessão seja invadida 100%, mas com alguma abordagem podemos reduzir o tempo de um invasor invadir a sessão.

Método para impedir o hijaking da sessão:

1 - sempre use sessão com certificado ssl;

2 - envie o cookie da sessão apenas com a ativação definida para true (evite que o javascript acesse o cookie da sessão)

2 - use o ID de regeneração da sessão no login e logout (nota: não use a regeneração de sessão em cada solicitação, porque se você tiver uma solicitação ajax consecutiva, poderá criar várias sessões.)

3 - definir um tempo limite da sessão

4 - armazene o agente do usuário do navegador em uma variável $ _SESSION e compare com $ _SERVER ['HTTP_USER_AGENT'] a cada solicitação

5 - defina um cookie de token e defina o tempo de expiração desse cookie para 0 (até que o navegador seja fechado). Gere novamente o valor do cookie para cada solicitação (para a solicitação do ajax, não gere novamente o cookie do token). EX:

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

note Observação: não gere novamente o cookie de token com solicitação do ajax. note: o código acima é um exemplo. nota: se os usuários fizerem logout, o token do cookie deverá ser destruído, assim como a sessão

6 - não é uma boa abordagem usar o ip do usuário para impedir o hijaking da sessão, pois alguns ip do usuário mudam a cada solicitação. QUE AFETA USUÁRIOS VALIDOS

7 - pessoalmente eu armazeno dados da sessão no banco de dados, cabe a você qual método você adota

Se você encontrar algum erro na minha abordagem, corrija-me. Se você tiver mais maneiras de impedir a sessão de hyjaking, informe-me.

Alexandru
fonte
oi, estou tentando impedir o seqüestro de sessão (no asp.net) e considerou todas as etapas acima sugeridas. É um trabalho aproximado, mas quando eu uso o modo InPrivateBrowsing / anônimo do navegador, a sessão é invadida. Você pode sugerir algo adicional a ser adicionado na string sessionId?
Vishwanath Mishra
4

Certifique-se de não usar números inteiros incrementados para IDs de sessão. Muito melhor usar um GUID ou alguma outra sequência de caracteres gerada aleatoriamente.

Kibbee
fonte
3

Existem várias maneiras de criar proteção contra o seqüestro de sessão, no entanto, todas elas reduzem a satisfação do usuário ou não são seguras.

  • Verificações IP e / ou X-FORWARDED-FOR. Eles funcionam e são bem seguros ... mas imagine a dor dos usuários. Eles chegam a um escritório com WiFi, obtêm um novo endereço IP e perdem a sessão. Preciso fazer login novamente.

  • Verificações do agente do usuário. O mesmo que acima, a nova versão do navegador foi lançada e você perde uma sessão. Além disso, estes são realmente fáceis de "hackear". É trivial para hackers enviar seqüências de caracteres falsas de UA.

  • token localStorage. No logon, gere um token, armazene-o no armazenamento do navegador e no cookie criptografado (criptografado no servidor). Isso não tem efeitos colaterais para o usuário (o localStorage persiste por meio de atualizações do navegador). Não é tão seguro - é apenas segurança através da obscuridade. Além disso, você pode adicionar alguma lógica (criptografia / descriptografia) ao JS para ocultá-lo ainda mais.

  • Emissão de cookie. Esta é provavelmente a maneira correta de fazer isso. O truque é permitir que apenas um cliente use um cookie de cada vez. Portanto, o usuário ativo terá o cookie reemitido a cada hora ou menos. O cookie antigo é invalidado se um novo for emitido. Hacks ainda são possíveis, mas muito mais difíceis de fazer - hackers ou usuários válidos terão acesso rejeitado.

Escotilha
fonte
1

Vamos considerar que, durante a fase de login, o cliente e o servidor podem concordar com um valor secreto de sal. Posteriormente, o servidor fornece um valor de contagem a cada atualização e espera que o cliente responda com o hash do (segredo salt + count). O seqüestrador em potencial não tem como obter esse valor secreto de sal e, portanto, não pode gerar o próximo hash.

davej
fonte
3
Mas como você deseja armazenar esse sal no lado do cliente para que ninguém possa roubá-lo?
Dcortez
1

AFAIK, o objeto da sessão não está acessível no cliente, pois é armazenado no servidor da web. No entanto, o ID da sessão é armazenado como um Cookie e permite que o servidor da Web rastreie a sessão do usuário.

Para impedir o seqüestro de sessão usando o ID da sessão, é possível armazenar uma cadeia de hash dentro do objeto de sessão, criada usando uma combinação de dois atributos, endereço remoto e porta remota, que podem ser acessados ​​no servidor da Web dentro do objeto de solicitação. Esses atributos vinculam a sessão do usuário ao navegador em que o usuário efetuou login.

Se o usuário efetuar login de outro navegador ou de um modo anônimo no mesmo sistema, o endereço IP permanecerá o mesmo, mas a porta será diferente. Portanto, quando o aplicativo é acessado, o usuário recebe uma identificação de sessão diferente pelo servidor da web.

Abaixo está o código que eu implementei e testei, copiando o ID da sessão de uma sessão para outra. Funciona muito bem. Se houver uma brecha, deixe-me saber como você a simulou.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

Usei o algoritmo SHA-2 para fazer o hash do valor usando o exemplo dado em SHA-256 Hashing na baeldung

Fico na expectativa dos seus comentários.

Jzf
fonte
@ zaph me desculpe, mas eu não adicionei a resposta para ganhar rep. O ponto também não é a criptografia SHA-2. Mas o fato de eu ter sido capaz de detectar o uso do ID da sessão de outro usuário Cookie na sessão de outro usuário, ou seja, seqüestro de sessão, como na pergunta original. Testei minha solução e achei que funciona. Como não sou especialista nisso, gostaria que a comunidade verifique se minha resposta é boa o suficiente. Talvez você possa ver o que meu snippet de código faz e decidir se ele responde à pergunta. Obrigado!
Jzf
@ zaph Obrigado por apontar o erro. Atualizei minha resposta conforme sua sugestão. Remova seu voto negativo se você acha que a resposta é útil.
Jzf
0

Para reduzir o risco, você também pode associar o IP de origem à sessão. Dessa forma, um invasor precisa estar dentro da mesma rede privada para poder usar a sessão.

A verificação de cabeçalhos de referência também pode ser uma opção, mas esses são mais facilmente falsificados.

Julio Cesar
fonte
7
não, você não pode usar o IP de origem, pois ele pode mudar - por meio de IPs dinâmicos, alterados quando um usuário é desconectado temporariamente ou pelo uso (implícito ou explícito) de um farm proxy. Além disso, seqüestradores sessão provenientes do mesmo ISP pode usar o mesmo proxy e IP como um usuário legítimo ...
Olaf Kock
1
PHP-Nuke tem uma página bem sobre a sua abordagem sessão, e eles falar em detalhes sobre como ligar para o IP não funciona com todos os ISPs phpnuke.org/...
Sembiance
4
Mudar os IPs é muito comum nos provedores de internet móvel. Com a Vodafone, meu IP muda com TODAS as solicitações.
Blaise
1
Um pouco de um post antigo, mas para promover isso. Os IPs são, como mencionado, uma má ideia. Como mencionado, os usuários móveis tendem a percorrer IPs. Alguns ISPs no passado também tinham IPs móveis (como a AOL), no entanto, essa abordagem está se tornando mais popular agora com a escassez de IPs IPv4. Tais ISP incluem Além disso net e BT
Peter
-15

Proteger por:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;
Nima
fonte
12
Não vejo o que você está fazendo aqui.
Samayo