• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

samuca

Login Seguro

26 mensagens neste tópico

Boas...

Ando a fazer um site para uma loja e estou a fazer um sistema de login. o sistema já está a funcionar bem, mas gostava de saber se tem algum problema de segurança, pois é uma das minhas preocupações.

//recebe a página escolhida pelo utilizador
$pagina = $_GET['pagina'];

//Recebe os dados do login
$username= $_POST['username'];
$password= $_POST['password'];
//recebe o tempo actual
$time=time();

//Define os parâmetros da sessão
$tempo = 1600;  //tempo da sessão em segundos
session_set_cookie_params($tempo, "/");
session_name("Loja");
session_start();

if ($pagina=="logout"){
	session_unset();
	session_destroy();
	include'pages/inicio.php';
}


//Verifica se os dados do login estão correctos
if ($username && $password) { 
	$password = md5($password);
	$consulta = "select * from users where nome='$username' and password='$password'";
	$result = mysql_query($consulta, $conexao);

	$rows = mysql_num_rows($result);
	if ($rows == 1)
	{
  			$_SESSION['username']=$username;
	}
	else{
		$login_error = true;
	}
}code]

Este código guarda o nome do utilizador numa variavel de sessão, não seria melhor guardar somente a ID da sessão e guardar o utilizador a que corresponde este id numa tabela da base de dados?

Alguém me pode dizer como posso melhorar a segurança deste pequeno script?

Obrigado

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

1º Esse md5 não está ai a fazer nada.

2º Validar os dados para não sofrer com um SQL Injection.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

1º Esse md5 não está ai a fazer nada.

2º Validar os dados para não sofrer com um SQL Injection.

1º Esse md5 é necessário ali porque a password já está encriptada na base de dados, e para poder comparar preciso de encriptar a password que recebi do formulário de login.

2º Validar os dados? Como? Não percebi muito bem

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Imagina que o user introduz o $username vaiporcima'#

Se a BD for MySQL qual é o resultado?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Imagina que o user introduz o $username vaiporcima'#

Se a BD for MySQL qual é o resultado?

o mais provável é que o php fizesse escape do caracter ', por isso não devia ser muito problemático.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Pode estar activo as Magic Quotes, ou não!

Na minha opinião estragam mais do que ajudam. Mas é uma hipotese para quem não pretende fazer mais nada.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bem, 1º o md5 é preciso e está correctamente aplicado!

Falta apenas fazeres, como o shunny disse, o escape a mysql injections. Usa o mysql_real_escape_string();

Eu uso esta função que vi no php.net:

//Evita o mysql injection
function escape($value) {
   // Stripslashes
   if (get_magic_quotes_gpc()) {
       $value = stripslashes($value);
   }
   
   // Quote if not a number or a numeric string
   if (!is_numeric($value)) {
       $value = "'" . mysql_real_escape_string($value) . "'";
   }
   
   return $value;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Campos que serão colocados na BD e que posteriormente serão apresentados na página também têm de ser validados contra HTML e JavaScript. Não faço ideia se o get_magic_quotes_gpc faz isso.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@shumy

Acho que estas a falar de XSS se for isso então esse código resolve...

<?php

function xss_protect( $data ) {

  $desinfectar = array('');
  $Limpo = array();

  $XSS = array( '/<[^>]*script*\"?[^>]*>/i', '/<[^>]*object*\"?[^>]*>/i',
               '/<[^>]*iframe*\"?[^>]*>/i', '/<[^>]*applet*\"?[^>]*>/i',
               '/<[^>]*meta*\"?[^>]*>/i', '/<[^>]*style*\"?[^>]*>/i',
               '/<[^>]*form*\"?[^>]*>/i' );

  $Limpar = preg_replace( $XSS , $desinfectar, $data );
  array_push( $Limpo, $Limpar );

return $Limpo[0];
}

echo xss_protect( $_REQUEST['varN'] ); //$_POST, $_GET, $_COOKIE...

?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bem, 1º o md5 é preciso e está correctamente aplicado!

Falta apenas fazeres, como o shunny disse, o escape a mysql injections. Usa o mysql_real_escape_string();

Eu uso esta função que vi no php.net:

//Evita o mysql injection
function escape($value) {
   // Stripslashes
   if (get_magic_quotes_gpc()) {
       $value = stripslashes($value);
   }
   
   // Quote if not a number or a numeric string
   if (!is_numeric($value)) {
       $value = "'" . mysql_real_escape_string($value) . "'";
   }
   
   return $value;
}

Estive a pesquisar sobre MySQL injection e resolvi aplicar a função que o Bruno colocou. Quanto a isso já está protegido. Obrigado

Agora a minha dúvida está na seguinte linha:

$_SESSION['username']=$username;

Eu guardo o username na sessão. Não seria guardar apenas um ID na sessão e o username numa tabela da BD que guarda os utilizadores online? Ou não faz diferenças a nível de segurança?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Depois de fazer o sistema todo com a vossa ajuda apareceu-me outro problema. Eu tenho uma função que serve para validar se o utilizador é administrador ou não, e se este não for administrador redirecciona-o para a página index.php.

function validar($us)
{
	//Verifica se o utilizador que está a aceder a uma página privada é administrador ou não
	//Se o utilizador não for administrador ou não estiver registado, é redireccionado para a página index.php

	$consulta = "Select * from users where nome = '$us' and nivel='1'";
	$result = mysql_query($consulta, $conexao);

	if(mysql_num_rows($result)==0){
		header("Location: index.php");
	}
}

Mas esta função dá-me o seguinte erro:

Warning: mysql_query(): supplied argument is not a valid MySQL-Link resource in C:\Programas\xampp\htdocs\projecto\admin.php on line 19

Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in C:\Programas\xampp\htdocs\projecto\admin.php on line 21

Warning: Cannot modify header information - headers already sent by (output started at C:\Programas\xampp\htdocs\projecto\admin.php:19) in C:\Programas\xampp\htdocs\projecto\admin.php on line 22

Mas o que é mais estúpido é que se eu meter o código que está dentro da função, fora da função já não dá erro nenhum e funciona na perfeição.

Alguém me explica qual é o problema?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Verifica qual é o conteudo dessa $conexao.

A variavel $conexao é o resultado da conexão ao servidor mysql.

//conectar ao servidor MySQL
$conexao = mysql_connect("localhost","teste","teste");
if (!$conexao) {
   	die('Erro de conexão: ' . mysql_error());
}

//escolhe a base de dados
mysql_select_db("loja",$conexao);

Porque é que este código só dá warning se estiver dentro da função?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

OK, eu sei. Mas essa variavel provavelmente tem local scope, e não tem o link de ligação MySql

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

OK, eu sei. Mas essa variavel provavelmente tem local scope, e não tem o link de ligação MySql

Pois, deve ser esse o problema. Não sabia que o PHP era diferente neste pormenor. Para resolver o problema é só adicionar esta linha dentro da função?

global $conexao;

Ou é preferível passar a variável por referência?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu em geral não gosto de variaveis globais. Não que dizer que não possam existir excepções.

Neste caso até nem parece mal ser global. Mas se estiveres a programar no paradigma OOP, é preferivel ser uma variavel da classe. Ou melhor...  ter uma classe que te prepara a conexão e trata os erros.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas,

Para não estar a abrir um novo tópico, vou escrever a minha dúvida já aqui. Neste momento tenho um formulário com a seguinte estrutura:

<form action="login.php" id="login" name="login">
  <input type="text" name="username" id="username">
  <div class="nav-body-login">Password:</div>
  <div id="form2">
  <input type="password" id="password" name="password">
  </div>
  <div id="submit_form">
  <input type="submit" id="submit" name="submit" value="Login">
</form>

E o ficheiro que valida o formulário é o ficheiro login.php, com o seguinte código:

<?php

//Evita o mysql injection
function escape($value) 
{
// Stripslashes
if (get_magic_quotes_gpc()) 
{
	$value = stripslashes($value);
}
// Quote if not a number or a numeric string
if (!is_numeric($value)) 
{
	$value = "'" . mysql_real_escape_string($value) . "'";
}

	return $value;
}

session_start();

$time = time();

error_reporting(E_ALL);
$script_base = dirname($_SERVER['SCRIPT_FILENAME']);  //define o root do ficheiro...
define('SCRIPT_BASE', $script_base);

include SCRIPT_BASE.'/includes/mysql.class.php';
include 'config.php';		//inclui o ficheiro de instalacao

$ligacao = new MySQL_DB_Connector; //faz a ligacao a classe que esta no ficheiro mysql.class.php
$ligacao->connect($host, $username, $password); //os valores $host, $username e $password estão no ficheiro config.php
mysql_select_db($database) or die("ERRO: Impossível escolher a base de dados: ".mysql_error());

if(isset($username) and isset($password)) //se tiverem sido introduzidos password e username...
{
$username = $_POST['username'];
$password = $_POST['password'];
//escape($password); //faz uso da função que escrevi acima, que evita o mysql injection
//$password = md5($password); //encripta a password
$query = "SELECT * FROM utilizador WHERE nome = '$username' AND password = '$password'";
$resultado = mysql_query ($query);

$array = mysql_fetch_array($resultado, MYSQL_ASSOC);

$id = $array["id"];
$email = $array["email"];
$permissao = $array["permissao"];

$rows = mysql_num_rows($resultado);

if($rows == 1) //se devolver resultado...
{
	$_SESSION['username'] = $username;
	$_SESSION['password'] = $password;
	$_SESSION['id'] = $id;
	$_SESSION['email'] = $email;
	$_SESSION['permissao'] = $permissao;
	?><script language="JavaScript">
			window.location = "admin/admin.php";
			</script><?php
}
if($rows == 0)
{
	?>
	<script language="JavaScript">
			window.location = "index.php";
			</script>
	<?php
	$erro = array();
	$erro [] = 'Impossivel fazer login !';
	return $erro;
}
}

?>

Ando aqui às voltas e ainda não consegui detectar qual o erro que está a fazer com que a página volte sempre ao index.php.

Alguém me pode ajudar?  :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tenta passar

if($rows == 1) //se devolver resultado...

para:

if($rows != 0) //se devolver resultado...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tenta passar

if($rows == 1) //se devolver resultado...

para:

if($rows != 0) //se devolver resultado...

Continua a não dar. Mais uma vez, verifiquei se os dados que estava a introduzir no form eram os mesmos que estão na tabela e estes realmente correspondem. Não percebo, portanto, de onde provém este problema.  :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Assim à primeira vista, falta-te fechar um <div> no formulário. Quanto ao código, não uses JavaScript para redireccionar uma página... :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Assim à primeira vista, falta-te fechar um <div> no formulário. Quanto ao código, não uses JavaScript para redireccionar uma página... :cheesygrin:

Isso eu tenho lá. O código html tem continuação, pelo que achei que não valia a pena estar a postá-lo todo.

Se não user javascript para redireccionar páginas, terei de usar o comando header(), no entanto quando se usa o header costuma dar um erro qualquer... :P

Já não sei por onde pegar nisto sinceramente. Vai sempre para a página principal... ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Poe assim:

if($rows == 0)
{
	echo "<script language=\"JavaScript\">
		window.location = \"index.php\";
		</script> ";
	$erro = array();
	$erro [] = 'Impossivel fazer login !';
	return $erro;
}
}

?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Poe assim:

if($rows == 0)
{
	echo "<script language=\"JavaScript\">
		window.location = \"index.php\";
		</script> ";
	$erro = array();
	$erro [] = 'Impossivel fazer login !';
	return $erro;
}
}

?>

Já tinha tentado fazer isso e inclusive com o comando print e printf. Continua a não funcionar. Ás tantas terei de refazer o código para ver se descubro qual o erro...

Se entretanto alguém tiver mais alguma sugestão, por favor diga-a. :cheesygrin:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tens a certeza que o login tá mesmo correcto? É que tens ali:

//$password = md5($password); //encripta a password

É suposto esta linha estar como comentário?

A password que guardas na tabela está encriptada? Se está, é esse o problema, tens que tirar o comentário dessa linha e já agora da linha acima.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora