How best to create a login system with PHP [closed]

closed . This question needs to be more objective and is not currently accepting answers.

want to improve this question? update the question to focus on just one problem when edit it .

Closed 1 year ago .

improve this question

I'm making a small system, and to access it, the user enters the login and password.

How best-safe and simple - to make the login and password system?

Author: Tiago S, 2014-01-31

6 answers

For secure authentication it is necessary to identify several points.

Some items you should take care of:

  • SQL Injection
  • password encryption
  • brute force attack
  • XSS attacks
  • CSRF attacks
  • protect session files
  • Protect system files

1 - starting

Set a hash that will be used by your entire system. an example is

define( 'SECURITY_HASH', 'uma frase qualquer ou letras aleatórias com números e simbolos' )

2 - Create your table in the database

Table suggestion

id
email
username
password
keymaster
last_ip
last_access
active
created_at
uptaded_at

3 - User Registration

When registering validate if a valid email has been passed, if the username field is in the correct format, and generate a hash for keymaster and use that hash to encrypt the password.

To validate the email use

if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
    echo "This ($email_a) email address is considered valid.";
}

An example of how to generate the hash

crypt( rand(99999) . time() .  $_SERVER["REMOTE_ADDR"], SECURITY_HASH );

A safer way to use this function is to use some $2a$ at the beginning of the second parameter to identify the type of encryption that should be used. Getting as follows:

crypt( rand(99999) . time() .  $_SERVER["REMOTE_ADDR"], '$2a$07$' . SECURITY_HASH );

Where $2a$ specifies the Blowfish algorithm and 07$ the cost to generate the hash.

Or if you are using php 5.5 you can use the password_hash () function. Learn more at http://br1.php.net/manual/en/function.password-hash.php

$_SERVER["REMOTE_ADDR"] // Obtem o IP do usuário

Store the user'S IP and last Access dates, and when it was created.

Leave the user inactive (field active = 0) and validate the registered email by sending a confirmation email.

In the confirmation email you enter a link of type

http://www.dominio.com.br/validateuser.php?key={hash do resultado da concatenação do keymaster e SECURITY_HASH}

This url will change the active field from 0 to 1, indicating that the user has been activated.

4 - Login

For login you must receive the form data and validate it, checking if it is as expected.

Search for information of the user in the bank, using only the username indicated.

With the data you obtained from the bank, encrypt the password entered by the form using the user's keymaster, the same procedure as the registration.

Compare the password you got from the bank with the password you received from the encrypted form if they are identical, log in.

5 - Basic Care

To get data passed via post or GET, avoid using variables Pure Global. To do this, use filter_input().

Read about in the documentation: http://www.php.net/manual/en/function.filter-input.php

--

To ensure that data sent via form has been performed from your server, create a hash and store in session. Add this hash in a hidden field of the form. When receiving the form values, verify that the hash that came from the form exists and is the same as the session.

Renew hash whenever you are displaying a form.

This link has a complete example on preventing this type of attack https://www.owasp.org/index.php/PHP_CSRF_Guard

--

  • never use register_globals set to on
  • Do not validate your forms only in javascript, because if the user is with javascript disabled it will pass straight through.

  • Use PDO by validating all variables before passing them to a SQL.

  • Configure in php.ini the following session.cookie_httponly = 1 . This tells the browser not to expose cookies to side client languages like javascript.
  • Name All files with the extension .php never with extension like .inc, .conf, etc.
  • avoid using md5 as encryption, use bcrypt as the algorithm is much more secure.
  • save the session in the database
  • set a domain for your cookie
  • count as login attempts and the time between them to prevent robberies.
  • in production leave display_errors off
  • generate error logs and send to your email, this makes it easy to identify hacking attempts.
  • beware of the permissions of your files on the server, ensure that only apache has permission on them.

Some links useful.

To implement the "Remember Me" I made a description in another answer here in StackOverflow

 96
Author: marcusagm, 2017-04-13 12:59:44

The best authentication is non-authentication

Follow some recommendations:

Do not reinvent the wheel

If possible use other sites to authenticate on yours. There is OpenID technology that allows this, and it is very easy. Facebook OpenId is the stackoverflow website itself: you can link your stackoverflow user to a Google account or Facebook account for example. This way you delegate the security of your site to other sites that-theoretically-are more reliable. At least access logon security.

Never, ever save passwords

Saving the username / password combination is the nightmare of any sysadmin and developer. The first option (OpenId) is the most secure. However, if OpenId is not an option-let's say it's a site that is on an Intranet that does not have Internet access - the way is to save username and password. Thus, the best approach is to save the password of such so that in case of some kind of theft of the database (from the table of users and passwords), you give work to the hacker when it comes to finding the password. That means...

Never save passwords in plain text

The first approach that everyone does (I've done... in 2002!) is to save passwords in plain text. Take the test: register on any website and click on the "Forgot my password" option. What should happen? The site will send you a message asking you to join a Specific URL, enter a new password, and this request will expire in x minutes or in y hours. What not should happen, under no circumstances is the site sending an email to you with the password you forgot. If this happened, then put this site on a blacklist, as it saves the passwords in plain text. On the other hand...

If you are going to use hash, think carefully

First was the plain text. Now you have learned and want to"evolve". Do what? Of course, it uses a generation algorithm of hash code to hide the password. Basically, a hash algorithm takes a series of bytes, makes a pretty crazy count involving summations and unique O's, twists and twists and generates a code: the hash code referring to the series of bytes that was used as input. It is practically impossible to infer the password just by looking at the generated hash code. It's a one-way routine, so to speak. "Perfect! I'll use hash and get along!" Be... just not. Let's assume that you chose the MD5 algorithm to generate your hash code. In the face you will have two problems:

  1. If the guy has a cool computer and a little time, he manages to "break the hash". What do you mean? Let's assume that the password entered gave a hash code aaaaabbcc0011 (it's just an example, the MD5 hash code has 32 hexadecimal digits). The hacker then uses a brute force algorithm that generates passwords until one of them gives the same hash code as the hash code of the original password. Detail: the password generated by the hacker may be totally different from the original password. This phenomenon is called a collision, and in the case of MD5 it happens with some ease;

  2. But the real hacker knows that users don't even call passwords, so what does he do? It uses a "password catalog". Want an example? The most common password on several sites is the notorious string 12345678. The hacker gets your table of users and passwords and notes that several of them are like this: 25d55ad283aa400af464c76d713c07ad. He doesn't even think twice: enter as password 12345678 and be happy. On the Internet there are several catalogs with the hash code of the most common passwords. Because of that...

Throw a little salt to taste

One way to further complicate the hacker's work is to put salt in the hash generation. "What do you mean?". It's simple: you generate any random alphanumeric code, and at the time of generating the hash, you include that code and preferably generate the hash again. Let's go back to the example of 12345678. Let's imagine that I generated a random salt like this 1adef56ghdfr43256yb. When I generate the MD5 code of 12345678, we'll have that acquaintance of ours up there. Then I take our acquaintance, along with salt and... I generate MD5 again! Look at the result: 7fb7daece2240e3ab134d6d4f9fe29fd. And if I do this one more time, I get: 1d2e962f721cee69fb3bca0d5ce9394b. I can do this as many times as I want, as long as I repeat the procedure the moment the user tries to authenticate to the site. Some important observations:

  1. The Salt it should be different for each user. If it is the same salt for all users, the generated code will be the same and then just the hacker finds a mané with password 12345678 that he (or she) finds the others;

  2. The Salt needs to be saved in the database. Nothing prevents it from being in different tables, as long as it does not degrade the performance;

  3. Each time the user changes the password, also change the Salt. It's one more Guarantee;

Security depends on password, and goes beyond it

Well, even with salt it is best not to abuse to avoid the evils of salt, you could, for example, use other hash algorithms such as SHA1 or SHA2 combined with salt. There is also the possibility to encrypt the password directly in the database, but this is usually not an option (especially on shared hosts). So, since the way is to save password and keep it in the bank, here are the end points. If you do this, the chance of something happening it will decrease a lot and your site will be more secure beyond login:

Disable register_globals, for God's sake!

REGISTER_GLOBALS in PHP is the capeta, the tinhoso. Simple as that. How does it work? Let's assume your form has a named Field... name (sorry, my creativity ended up up there). With register_globals disabled, to read the contents of this form field, you use $_GET['nome'] or $_POST['nome']. Now if register_globals is on, the engine PHP will "magically" create a variable called... nome name! You can do very ugly things on websites with register_globals enabled. The default in PHP 5 is off, but there is sysop that has to reactivate it on account of manes sites that still use this feature. If your sysop is in a good mood, it will let you configure your application's register_globals in the file .htaccess located in the root directory of your site (this is a bit out of the scope of stackoverflow, but look in the group sites stackexchange you think).

Concatenate SQL with parameters: your hacker friend thanks

When querying the database, always use methods and routines that support bound parameters. If you are from PDO( I recommend), it would be something like this:

$banco = new PDO(...);
$comando = $banco->prepare("SELECT ID, NOME FROM USUARIOS WHERE LOGIN = :login AND SENHA = :senha");

// Vamos considerar que você já pegou o sal daquele usuário e já aplicou os esquemas.
// Dá para fazer dentro do banco, se você preferir. É até melhor...

$comando->execute(array(':login' => $login, ':senha' => $senha_com_sal));

if ($comando->fetch()) { // Usuário logado!

} else { // Usuário incorreto ou a senha está incorreta!

}

Why is this approach better than simply concatenating the password and single quotes? For the hacker, concatenation allows a type of attack called "SQL Injection". Usually he does it in a way that he puts certain characters inside one of the fields (that of the name for example) and then he manages to turn an innocent SELECT that should bring 0 or 1 line, in a powerful SELECT that brings all the rows of the table. Depending on the hacker's experience (and the programmer's inexperience), he may even use insert's and update's and detonate the site, or open it entirely. Search for SQL Injection attacks on the Internet and get ready for the scenes of horror!

One note: This bound parameters system also works with mysqli and the like. Search the documentation. It's totally worth it.

Technology does not beat good social engineering

As I said earlier, a lot of people (a lot of them) use passwords like 12345678, superman, etc. for the most diverse purposes. The best way to avoid attacks (or make them even harder) is to force the user to enter passwords with minimal security. Establish rules for the creation of passwords by users. A few simple rules, but they can make all the difference: 1. The password must be at least 8 characters long; 2. The password must have at least 2 alphabetic characters (a-z); 3. The password must have at least 2 numeric characters (0-9); 4. The password must have at least 2 uppercase alphabetic characters (A-Z); 5. The password must have at least 1 special character, such as$&@#!% etc.

And so on.

Many of these tips I I took from my experience and also from this video (in English): http://youtu.be/8ZtInClXe1Q

Good luck and tell us how it went.

 45
Author: Robson França, 2014-02-06 02:25:14

With more and more reports of hacking activity in the news, developers are looking for the best alternatives to ensure greater security on their websites. If your site has a membership system, it may be at risk such as being hacked and having your users ' information compromised. This guide will introduce you to the best ways to create your user system and login as securely as possible. Following this guide, you will be able to learn how to prevent against various types of attacks that hackers can use to gain control of the account of other users, delete accounts and/or modify data.

Required Materials

Since we will be using the PHP class set MYQLI_* to access our mySQL database, you will need the following versions of PHP and mySQL: PHP version 5 or higher MySQL version 4.1.3 or higher To check the version of PHP and mySQL on your server, use the function phpinfo ();.

Configure your server

Install PHP and MySQL on your server. Most webhosts will have php and mySQL already installed, so you just need to check if they are with the most current versions of each one for this guide to work.

Configure MySQL database

1 create a MySQL database. In this guide, you will create a database called "secure_login" (secure login). You can do this through Phpmyadmin or use the following SQL command to create it for you.

Database creation code:

CREATE DATABASE `secure_login`;

Note: some host services do not allow you to create databases by phpMyAdmin, in cases where you will need to use cPanel.

2 create a user with only SELECT, UPDATE, and INSERT privileges.

This means that if there is ever a security breach in your script, the hacker will not be able to delete or extract anything from our database. Using this user, you can do pretty much anything you want in your application. If you are really paranoid, create a different user for each role.

  • user: "sec_user"
  • password: "eKcGZr59zAa2BEWU"

User Creation code:

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE ON `secure_login`.* TO 'sec_user'@'localhost';

Note: it is a good idea to modify the user password in the above code when running it on your own server. (Be sure to modify your PHP code as well.) Remember that it does not have to be a password that you can remember, so make it as complicated as possible.

3 create a MySQL Table called "members".

The following code creates a table with 5 fields (id, username, email, password, salt).

Create the table " members:

CREATE TABLE `secure_login`.`members` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  `username` VARCHAR(30) NOT NULL, 
  `email` VARCHAR(50) NOT NULL, 
  `password` CHAR(128) NOT NULL, 
  `salt` CHAR(128) NOT NULL
) ENGINE = InnoDB;

We we use the CHAR data type for fields that we know the size (amount of characters), such as password and salt fields that will always be 128 characters long. By using CHAR here, you will be saving processing.

4 create a table to store login attempts.

We will use this table to store a user's login attempts. It is in this way that we will prevent attempts to attack with brute force or brute force.

Create the "login_attempts" table:

CREATE TABLE `secure_login`.`login_attempts` (
  `user_id` int(11) NOT NULL,
  `time` VARCHAR(30) NOT NULL 
) ENGINE=InnoDB

5 create a Test line in the "members" table.

Since we are not creating a signup page, it will be important that you are able to test your login script. Below is the script to create a user with these details:

Add Test user:

INSERT INTO `secure_login`.`members` VALUES(1, 'test_user', '[email protected]', '00807432eae173f652f2064bdca1b61b290b52d40e429a7d295d76a71084aa96c0233b82f1feac45529e0726559645acaed6f3ae58a286b9f075916ebf66cacc', 'f9aab579fc1b41ed0c44fe4ecdbfcdb4cb99b9023abb241a6db833288f4eea3c02f76e0d35204a8695077dcf81932aa59006423976224be0390395bae152d4ef');

Create a database connection page

1 create a database connection page.

This is the php code that we will use to connect to the MySQL database. Create a new php file called " db_connect.php " and add the following code. You can then include the file on any page that you want to connect to the database.

Database connection (db_connect.php):

define("HOST", "localhost"); // O host no qual você deseja se conectar.
define("USER", "sec_user"); // O nome de usuário do banco de dados.
define("PASSWORD", "eKcGZr59zAa2BEWU"); // A senha do usuário do banco de dados. 
define("DATABASE", "secure_login"); // O nome do banco de dados.

$mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
// Se você estiver se conectando via TCP/IP ao invés de um socket UNIX, lembre-se de adicionar o número da porta como um parâmetro.

Create PHP functions

These functions will do all the processing of the login script. Add all functions on a page called " functions.php".

1 start a secure PHP session.

It is important not to put just "session_start ()"; at the top of all pages on which you want to use php sessions, if you really are concerned about security, this is how you should do it. You will create a function called "sec_session_start", which will securely start a php session. You should call this function at the top of each page from which you want to access a php session variable.

Secure login function:

function sec_session_start() {
        $session_name = 'sec_session_id'; // Define um nome padrão de sessão
        $secure = false; // Defina como true (verdadeiro) caso esteja utilizando https.
        $httponly = true; // Isto impede que o javascript seja capaz de acessar a id de sessão. 

        ini_set('session.use_only_cookies', 1); // Força as sessões a apenas utilizarem cookies. 
        $cookieParams = session_get_cookie_params(); // Recebe os parâmetros atuais dos cookies.
        session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly); 
        session_name($session_name); // Define o nome da sessão como sendo o acima definido.
        session_start(); // Inicia a sessão php.
        session_regenerate_id(true); // regenerada a sessão, deleta a outra.
}

This function makes your login script much more secure. Prevents hackers from being able to access the session ID cookie through javascript (for example, in an XSS attack). It also uses the "session_regenerate_id ()" function, which generates the session id again every page refresh, helping to prevent a hijack attack on the session. Note: If you are using https in your login application, set the variable "$secure"to " true".

2 create a login function.

This function will check the email and password in the database and return a value "true") if both are correct and matching.

Secure Login function:

function login($email, $password, $mysqli) {
   // utilizar declarações preparadas significa que a injeção de código SQL não será possível. 
   if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM members WHERE email = ? LIMIT 1")) { 
      $stmt->bind_param('s', $email); // Vincula "$email" ao parâmetro.
      $stmt->execute(); // Executa a query preparada.
      $stmt->store_result();
      $stmt->bind_result($user_id, $username, $db_password, $salt); // obtém variáveis do resultado.
      $stmt->fetch();
      $password = hash('sha512', $password.$salt); // confere o hash de "$password" e "$salt"
      if($stmt->num_rows == 1) { // se o usuário existe
         // Nós checamos se a conta está bloqueada devido a várias tentativas de login
         if(checkbrute($user_id, $mysqli) == true) { 
            // Conta está bloqueada
            // Envia um email ao usuário comunicando que sua conta foi bloqueada
            return false;
         } else {
         if($db_password == $password) { // Checa se a senha na base de dados confere com a senha que o usuário digitou. 
            // Senha está correta!

               $ip_address = $_SERVER['REMOTE_ADDR']; // Pega o endereço IP do usuário. 
               $user_browser = $_SERVER['HTTP_USER_AGENT']; // Pega a string de agente do usuário.

               $user_id = preg_replace("/[^0-9]+/", "", $user_id); // Proteção XSS conforme poderíamos imprimir este valor
               $_SESSION['user_id'] = $user_id; 
               $username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // Proteção XSS conforme poderíamos imprimir este valor
               $_SESSION['username'] = $username;
               $_SESSION['login_string'] = hash('sha512', $password.$ip_address.$user_browser);
               // Login com sucesso.
               return true;    
         } else {
            // Senha não está correta
            // Nós armazenamos esta tentativa na base de dados
            $now = time();
            $mysqli->query("INSERT INTO login_attempts (user_id, time) VALUES ('$user_id', '$now')");
            return false;
         }
      }
      } else {
         // Nenhum usuário existe. 
         return false;
      }
   }
}

3 Brute Force Function.

Brute force or brute force attacks happen when hackers try thousands of different passwords on an account, either randomly through random passwords or through a word dictionary. In our script, if a user fails their login attempt more than 5 times, their account will be blocked.

Shout to login_check function:

function checkbrute($user_id, $mysqli) {
   // Retorna a data atual
   $now = time();
   // Todas as tentativas de login são contadas pelas 2 últimas horas. 
   $valid_attempts = $now - (2 * 60 * 60); 

   if ($stmt = $mysqli->prepare("SELECT time FROM login_attempts WHERE user_id = ? AND time > '$valid_attempts'")) { 
      $stmt->bind_param('i', $user_id); 
      // Executa a query preparada.
      $stmt->execute();
      $stmt->store_result();
      // Se houver mais de 5 tentativas falhas de login
      if($stmt->num_rows > 5) {
         return true;
      } else {
         return false;
      }
   }
}

Brute force or brute force attacks are difficult to prevent. Some forms of prevention that we can use are the use of CAPTCHA tests, blocking user accounts and adding a delay or time interval for failed login attempts, so that the user can not try to log in again for the next 30 seconds.

When faced with this problem, most developers simply block the address IP after a certain amount of failed logins. With various tools to automate the process, these tools can go through a series of proxies and even modify your IP on each request. Blocking all these IPs can mean that you are also blocking IPs from legitimate users.

4 check the login status.

This is done by checking the session variables "user_id"and " login_string". The session variable "login_string" has the IP address and browser information in the form of a hash along with the password. We use the IP address and browser information as it is very unlikely that the user will change the IP address or browser during their session. By doing this, you prevent a hijack attack on the session (session hijacking, literally).

Create the login_check function:

function login_check($mysqli) {
   // Verifica se todas as variáveis das sessões foram definidas
   if(isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string'])) {
     $user_id = $_SESSION['user_id'];
     $login_string = $_SESSION['login_string'];
     $username = $_SESSION['username'];
     $ip_address = $_SERVER['REMOTE_ADDR']; // Pega o endereço IP do usuário 
     $user_browser = $_SERVER['HTTP_USER_AGENT']; // Pega a string do usuário.

     if ($stmt = $mysqli->prepare("SELECT password FROM members WHERE id = ? LIMIT 1")) { 
        $stmt->bind_param('i', $user_id); // Atribui "$user_id" ao parâmetro
        $stmt->execute(); // Executa a tarefa atribuía
        $stmt->store_result();

        if($stmt->num_rows == 1) { // Caso o usuário exista
           $stmt->bind_result($password); // pega variáveis a partir do resultado
           $stmt->fetch();
           $login_check = hash('sha512', $password.$ip_address.$user_browser);
           if($login_check == $login_string) {
              // Logado!!!
              return true;
           } else {
              // Não foi logado
              return false;
           }
        } else {
            // Não foi logado
            return false;
        }
     } else {
        // Não foi logado
        return false;
     }
   } else {
     // Não foi logado
     return false;
   }
}

Creating processing pages

1 *create the page of login processing (process_login.php).*

Following our previous example, this should be called process_login.php. We will use the set of functions PHP mysqli_* because it is the most current extension of mysql.

Login processing page (process_login.php)

include 'db_connect.php';
include 'functions.php';
sec_session_start(); // Nossa segurança personalizada para iniciar uma sessão php. 

if(isset($_POST['email'], $_POST['p'])) { 
   $email = $_POST['email'];
   $password = $_POST['p']; // A senha em hash.
   if(login($email, $password, $mysqli) == true) {
      // Login com sucesso
      echo 'Sucesso: Você efetuou login.';
   } else {
      // Falha de login
      header('Lozalização: ./login.php?error=1');
   }
} else { 
   // As variáveis POST corretas não foram enviadas para esta página.
   echo 'Requisição Inválida';
}

2 create a logout script.

Your logout script should start the session, destroy it, and then redirect the user to some other page.

Logout Script (logout.php):

include 'functions.php';
sec_session_start();
// Zera todos os valores da sessão
$_SESSION = array();
// Pega os parâmetros da sessão 
$params = session_get_cookie_params();
// Deleta o cookie atual.
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
// Destrói a sessão
session_destroy();
header('Lozalização: ./');

Note: it might be a good idea to add CSFR protection here in case someone sends a link to this page in some way. The user will be disconnected.

3 registration page.

To create the password hash, you will need to use the following code:

Hash Script:

// A senha em hash do formulário
$password = $_POST['p']; 
// Cria um salt randômico
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
// Cria uma senha pós hash (Cuidado para não re-escrever)
$password = hash('sha512', $password.$random_salt);

// Adicione sua inserção ao script de base de dados aqui 
// Certifique-se de utilizar declarações preparadas
if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, email, password, salt) VALUES (?, ?, ?, ?)")) {    
   $insert_stmt->bind_param('ssss', $username, $email, $password, $random_salt); 
   // Execute a query preparada.
   $insert_stmt->execute();
}

Make sure that the value of $_POST ['p'] is already hashed from the javascript. If you are not using this method because you want to validate the password on the server side, be sure to use hash.

Create JavaScript Files

1 create a sha512 file.js.

This file is a javascript implementation of the sha512 hashing algorithm. We will use the hashing function so that our passwords are not sent in plain text. The file can be downloaded from http://pajhome.org.uk/crypt/md5/sha512.html

2 create the forms file.js.

This file will handle the hash of passwords for any form.

JavaScript form file (forms.js):

function formhash(form, password) {
   // Cria um novo elemento de entrada, como um campo de entrada de senha sem hash.
   var p = document.createElement("input");
   // Adiciona o novo elemento ao nosso formulário.
   form.appendChild(p);
   p.name = "p";
   p.type = "hidden"
   p.value = hex_sha512(password.value);
   // Certifica que senhas em texto plano não sejam enviadas.
   password.value = "";
   // Finalmente, submete o formulário.
   form.submit();
}

Create HTML pages

1 create the login form (login.php).

This is an HTML form with two text fields, called "email" and "password". We JavaScript will then generate the password hash and send the "email" and "p" (the password hash) to the server.

When logging in, it's best to use something non-public. For this guide, we are using email as a login; the username can be used later to identify the user. If the email is hidden, a new variable will be added for attempts to hack accounts.

HTML Login Form:

<script type="text/javascript" src="sha512.js"></script>
<script type="text/javascript" src="forms.js"></script>
<?php
if(isset($_GET['error'])) { 
   echo 'Erro ao Logar!';
}
?>
<form action="process_login.php" method="post" name="login_form">
   Email: <input type="text" name="email" /><br />
   Password: <input type="password" name="password" id="password"/><br />
   <input type="button" value="Login" onclick="formhash(this.form, this.form.password);" />
</form>

Note: even if we have encrypted the password so that it is not sent in plain text, it is recommended that you use the https protocol (TLS/SSL) when you are sending passwords.

Protecting Pages

1 page Protection Script.

One of the most common problems with authentication systems is that the developer forgets to check if the user is logged in. It is very important that you use the code below to check if the user is logged in. Page protection:

// Inclua a conexão com a base de dados e as funções aqui.
sec_session_start();
if(login_check($mysqli) == true) {

   // Adicione o conteúdo de sua página protegida aqui.

} else {
   echo 'Você não está autorizado a acessar esta página. Por favor, efetue login. <br/>';
}

End;)

Source: http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL

 20
Author: Walter Gandarella, 2014-02-06 00:50:35

Question: What is the best way to make a password login system with PHP?

Answer: there is no"the best way". there are several quality solutions, each one being the best within a specific context.

 10
Author: J. Bruni, 2014-02-05 20:43:51

When it comes to user authentication, " safe "and" simple " will hardly make sense. The way to have less work in this case, without sacrificing system security, is to use a framework that already implements this for you. Symfony2 provides an authentication library that can be used standalone, see docs.

My answer assumes that your interest is to create a system that will at some point go into production; your interest is educational you can use a simple hashing algorithm and save the combinations of name and password in a local database and then search further topics such as hashing, salting, etc.

 9
Author: Rodrigo Deodoro, 2014-01-31 17:07:05

In PHP use Argon2id , this is available in PHP 7.2:

$hash_str = sodium_crypto_pwhash_str($password, 
       SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
       SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

Then use sodium_crypto_pwhash_str_verify($hash_str, $password).

You can also use the Argon2i :

$hash_str = password_hash($password , PASSWORD_ARGON2I, [
          'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST, 
          'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST, 
          'threads' => PASSWORD_ARGON2_DEFAULT_THREADS
]);

Then use password_​verify($password, $hash_str).

If you are on an outdated version of PHP, then security doesn't seem to be your priority. If you are still using a "supported" version but do not have Argon2, use BCrypt: password_hash($password , PASSWORD_BCRYPT, ['cost' => 13]);. if neither BCrypt is available, then use PBKDF2.

Multiple answers you have serious problems!

  1. Use rand(), mt_rand() or uniqid() and even time()...

    These are all good for generating unique data, to some extent. Spotify uses mt_rand() to choose a random order of music, for this purpose it is good, it is fast. A game can use it to create the smoke effects, ok. Now, for passwords it doesn't have to be just unique. It needs to be unique, printable (for the attacker) and still have a distribution of equal results. Soon, an attacker cannot predict the next value and retrieve previously generated values. Depending on the generator, not even attacking the entropy pool, consumed to re-seed, will be able to know the bytes generated, why does not know the current state.

    mt_rand() will repeat all values, in the same order, after X numbers generated. In addition, with a sample of ~700 generated numbers you can predict all the next ones.

    The maximum Pearl is to use time(), look at your clock and you know the value, in fact it is unique (it is unixtime), but it is clearly predictable. In fact, it is not unique, if they attack the NTP server that you probably use to synchronize the date-time you will go back in time.

    Use random_bytes or simply read /dev/urandom, if applicable. These two are CSPRNG and should be used for these purposes.

  2. Use SHA-2, SHA-1, MD5, SHA-3....

    That it was made for general purpose, not for passwords. Passwords are inputs chosen by human beings and we are incompetent to choose good passwords. We can not remember extremely complex passwords, Many appeal to memories or personal data. This makes it vulnerable to pre-computed attacks or dictionary attacks.

    The best choices you have are BCrypt and Argon2i, both of which are available in PHP 7.2. While BCrypt and PBKDF2 are available from PHP 5.5. These are all key derivation (KDF) or also call Password Hashing, this differs from general purpose hashes such as SHA-2.

    In Argon2i the difficulty, which is customizable. This involves increased memory usage, increased parallel processing usage, and the number of rounds, iterations required for a single password. The higher the difficulty the greater the time to do the hashing of a single string. BCrypt has similar features, but not being possible to increase individually. PBKDF2 has only the amount of iterations (which is basically N * HMAC(), very roughly speaking), this is the worst of the best methods you can use.

  3. Use the salt and believe that it is salvation.

    The salt is not miraculous. In it does not delay an exhaustive search attack. If you have HASH(x) and HASH(x + y) the time difference to compute the two is extremely negligible, if y is few bytes it will be equal. Also if you do HASH(salt + senha) the attacker can ignore salt completely, if it is the same size (or larger) as the hash block.

    The salt was made solely so that two passwords are different from each other and only. If you have a function HASH(string, salt), and then do BCRYPT(x, y) and BCRYPT(x, z) the result for the same x will be different, because the salts (y and z) are different. This prevents an attacker from breaking multiple passwords at the same time, only.

    The cost against brute-force is much more complex, ranging from memory usage, parallelism, pre-computing capacity and even the number of targets. This is what is done in the use of Argon2, BCrypt and even reasonably in PBKDF2. These functions are not good because they use salt, salt is made for a different purpose of increasing than to increase the difficulty.

  4. Use == and ===.

    This is vulnerable to timming-attack. That's worth it for all languages, practically. Most languages use memcmp() or similar features, which makes it fast but not secure.

    But, not only that, PHP has a feature of having dynamic typing and this brings several unexpected effects for some. In general, never use ==, or you may see something like sha1('aaroZmOk') == sha1('aaK1STfY') return true. This is not a SHA-1 collision, this is just because both start with 0e and == does the job of converting and then become valid, which does not occur with ===.

    PHP has the hash_equals(), although the name it can be used for any purpose, ie hash_equals('a', 'a') works. Despite the prefix hash_ the strings involved do not have to be a cryptographic hash.

 7
Author: Inkeliz, 2018-07-06 19:54:34