Ir para o conteúdo

Criar sistema de login seguro

<?php
session_start();
# Isto será o script responsável pelo processamento do login:

if( isset( $_SESSION['userdata'] ) )
{
  # Já está logado, toca a ir pro inicio
  header('location: /');
  exit();
}

if( $_POST )
{
  try
  {
    if( trim($_POST['username']) == '' )
      throw new Exception('O campo Username é obrigatório',1);
    elseif( empty( $_POST['password'] ) )
      throw new Exception('O campo Password é obrigatório',1);

    # Aqui validamos se a token que gerámos ao mostrar o formulário é igual
    # à que está em sessão. Assim "garantimos" que o $_POST é enviado através do
    # nosso formulário :)
    if( $_POST['csrf_token'] != $_SESSION['csrf_token'] )
      throw new Exception('Por favor use a nossa página para efectuar a operação.',1);

    # Não queremos surpresas:
    $_POST['username'] = strip_tags( trim( $_POST['username'] ) );

    mysql_connect('localhost','user','pwd') or throw new Exception('Não foi possível ligar ao servidor de base de dados - '
. mysql_error(),2);
    mysql_select_db('basededados') or throw new Exception('Não foi possível ligar à base de dados - ' . mysql_error(),2);

    $query = 'SELECT * FROM users WHERE username = "' . mysql_real_escape_string( $_POST['username'] ) . '" AND active = 1';
    $user_result = mysql_query( $query ) or throw new Exception( 'Ao executar a query "' . $query . '" deu erro!',2);

    # Assumo que o username é único...
    if( mysql_num_rows( $user ) == 1 )
    {
      # Vamos buscar o user e comparamos a password:
      $user = mysql_fetch_object( $user_result );
      mysql_free_result($user);

      /**
       * Antes de comparar a password, gostaria de alertar para que se guarde a password
       * na base de dados em forma de Hash, para que caso consigam infiltrar-se no site e/ou
       * servidor (seja base de dados seja http) eles não consigam obter as passwords reais.
       * 
       * É que muita gente usa a mesma password para vários serviços - e-mail, facebook, etc...
       */
      $salt_key = "1234**1234@@AAAZZZaaaaZZZZ!";
      $password = sha1( $_POST['password'] . $salt_key );
      if( $user->password != $password )
        throw new Exception('Wrong Password',1);

      # Ora chegamos até aqui, está tudo bem... vamos criar a fingerprint e a sessão do utilizador:
      $salt_key = "Outra**Salt@@1231312001011!";
      $fingerprint = sha1($salt_key . getenv('REMOTE_ADDR') . $_SERVER['SERVER_NAME'] . $_SERVER['HTTP_USER_AGENT']
. gethostbyaddr ( getenv('REMOTE_ADDR') ) );

      $userdata = array(
        'id' => $user->id,
        'username' => $user->username,
        'name' => $user->name,
        'email' => $user->email,
        'usertype' => $user->usertype,
        'fingerprint' => $fingerprint,
        'timestamp' => time()
      );

      $_SESSION['userdata'] = $userdata;

      # Redirecciona-se para o inicio :) Ou para onde tiver que ser claro :D
      header('location: /');
      exit();
    }
    else
      throw new Exception('O Username definido não existe!',1);
  }
  catch( Exception $e )
  {
    # Aqui cai tudo o que é erro! =)
    switch( $e->getCode() )
    {
      case 1: # Problema visível
        echo $e->getMessage();
        break;
      case 2: # Problema da query! É melhor registar, e mostrar erro geral.
        echo 'Ocorreu um erro ao efectuar a operação, por favor contacte o suporte técnico.';
        error_log( 'Error n. ' . $e->getCode() . ' - ' . $e->getMessage(),0);
        break;
    }
  }
}

# Geramos um id único para gerar uma chave que servirá para validar se os 
# dados do formulário foram enviados pelo mesmo, ou é um post simulado :)
$csrf_token = uniqid(time());
$_SESSION['csrf_token'] = $csrf_token;
?>
<!-- LOGIN FORM -->
<form method="post" action="/login/">
<input type='hidden' name='csrf_token' id='csrf_token' value='<?php echo $csrf_token;?>' />
<label for='username'>Username</label> <input name='username' id='username' type='text'
value='<?php echo (($_POST['username']) ? $_POST['username'] : '');?>' /><br/>
<label for='password'>Password</label> <input name='password' id='password' type='password' value = '' /><br/><br/>
<input name='cmdSend' type='submit' value='LogIn' />
</form>
session_start();
# Script de validação da sessão:
$salt_key = "Outra**Salt@@1231312001011!";
$fingerprint = sha1($salt_key . getenv('REMOTE_ADDR') . $_SERVER['SERVER_NAME'] . $_SERVER['HTTP_USER_AGENT']
. gethostbyaddr ( getenv('REMOTE_ADDR') ) );

if(!$_SESSION['userdata'])
{  header('location: /login/'); exit(); }
elseif( !isset($_SESSION['userdata']['fingerprint']) || ($_SESSION['userdata']['fingerprint'] != $fingerprint) )
{  session_destroy(); header('location: /login/'); exit(); }
elseif( ( time() - $_SESSION['userdata']['timestamp']) > ( 60*5) )
{  session_destroy(); header('location: /login/'); exit(); }