New to security and wondering how secure this type of login is? I am not protecting any bank/financial data by any means but trying to secure somewhat sensitive data that shouldn't be exposed to the general public. I only require a password - no official logins are done.
This is in a file called access.php which houses a password input field.
<?php
session_start();
if (!isset($_SESSION['loggedIn'])) {
$_SESSION['loggedIn'] = false;
}
// sha256() password
$password = '13d249f2cb4127b40cfa757866850278793f814ded3c587fe5889e889a7a9f6c';
if (isset($_POST['password'])) {
if (hash('sha256',$_POST['password']) == $password) {
$_SESSION['loggedIn'] = true;
} else {
die ('That is the incorrect password - Please leave now');
}
}
if (!$_SESSION['loggedIn']):
?>
Then my index.php requires access.php at page load. Should access live outside the public directory? Am I missing anything else I should be considering?
New to security and wondering how secure this type of login is?
SHA-256: You're using the entirely wrong tool for the job. Use password_hash() and password_verify():
How to safely store a password
Cryptography terms explained for non-experts
Additionally, SHA-256 is vulnerable to length-extension attacks.
Using == to compare hashes has two vulnerabilities:
Timing attacks
Magic hash comparison (the more pressing concern)
So, to answer your question: Not very. The problem your code is trying to solve is well-known among security experts, and they've gone out of their way to make it simple for others to solve it. That's why password_hash()and password_verify() exist. Use them.
That said, welcome to software security. If you need some additional resources to aid your self-education, check out this application security reading list on Github.
Related
I need a page that is only shown to authorized uses.so i plan to use sessions.
There will only be a single user and the password wont change.So i plan to do something like this
<?php
session_start();
if(isset($_POST['password']) )
{
if($_POST['password']=="myhashedpassword" )
{
// auth okay, setup session
$_SESSION['user'] = $_POST['username'];
// redirect to required page
header( "Location: index.php" );
} else {
// didn't auth go back to loginform
header( "Location: loginform.html" );
}
} else {
// username and password not given so go back to login
header( "Location: loginform.html" );
}
?>
I was wondering about the security of this approach.I dont need total security.. hope its fair.
Three reasons why I would say not to do this:
You're comparing a plaintext password ($_POST['password']) with a constant string. Even if the constant string is hashed, your password isn't, so you're effectively treating the hash as a password now. Pass the hash.
Timing attacks.
Using == to compare hashes in PHP leads to unpredictable results.
Overall I think this would be frowned upon but it is not completely insecure because they are not seeing the plaintext password. It removes the need for someone to get access to say the database to get the hash and then trying to bruteforce it. So a bit easier.
Also, this will not work if($_POST['password']=="myhashedpassword" ) because you are comparing the hashed password to a plaintext password from the post. So you would really need to do
if( hash_algo($_POST['password']) == "myhashedpassword" ){//stuff}
My suggestion would be to do this as a normal authentication or add a flag to user accounts that have access to the page and check on that.
Never hardcode passwords. Some of the reasons are:
It is harder to keep source code secret than it is a key.
Any vulnerabilities in your site that allow reading of source code may reveal the password.
Passwords from development will end up in production.
It is impossible to change passwords without redeploying (you say it won't change, however what do you do in case of breach?).
I currently have a PHP Login System which logins by authenticating the Organisation Code the user enters, thus the database queried will be different.
includes.php
<?php
mysql_connect("mysql.example.com", $dbconn, "MySecurePassword");
mysql_select_db($dbconn);
?>
login.php
// $org is the Organisation Code, will be set when user clicks Login
$dbconn = $org;
include "includes.php";
// Omitted the $userid & $pw variables, assume there is no error, and that MySQL Injection is prevented already
$query = "SELECT * FROM `Login` WHERE `userid`=TRIM('$userid') AND `password`=TRIM('$pw' )";
$result = mysql_query($query);
if(mysql_num_rows($result)>0){
session_start();
$_SESSION['logged_in'] = $username;
header("Location: loggedinpage.php");
}
loggedinpage.php
<?php
session_start();
// As there is no fixed database, I've omitted the DB Connection
define('DS', TRUE); // used to protect includes
define('USERNAME', $_SESSION['logged_in']);
define('SELF', $_SERVER['PHP_SELF'] );
// Checks if user is logged in
if (!USERNAME) {
header("Location: login.php");
}
?>
Security Measure Taken
Passwords are hashed using SHA-512 and not stored in plaintext.
MySQL injection is prevented using mysql_real_escape_string()
I've omitted some code for ease to read, may I know if this way of checking if user is logged in is secure? If not, how can I improve it?
Thanks in advance!
Updated question to reflect the updates in comments
Assuming that your query works as intended and only returns a row when the match is exactly correct (e.g. no weird fuzzy matching through collate rules, but pure bin comparison), the authentication part is pretty much fine.
(You have been warned about SQL injection plenty, you're on your own there.)
Your security then boils down to this:
$_SESSION['logged_in'] = $username;
and the subsequent:
define('USERNAME', $_SESSION['logged_in']);
if (!USERNAME) {
header("Location: login.php");
}
And I suppose your question is about this part.
Then the answer is: the session part is fine, the blocking is not.
That's how sessions are used, yes, and they're reasonably safe by default; a user won't be able to somehow set the $_SESSION['logged_in'] value themselves, the value can only be set by your server, and presumably you're doing so only on successful authentication. Do read up about session hijacking, this is the only real vulnerability to the whole scheme.
The real problem is:
if (!USERNAME) {
header("Location: login.php");
}
Setting a header does not terminate the current page. If you're outputting sensitive information after this line, it will be sent to the client! You need to explicitly exit after setting the header.
Having said all this, we cannot tell you whether your system is "secure" because there may be any number of facepalm backdoors you have created which we're not seeing. In general I'd start with the following:
stop using mysql, use PDO or mysqli
bind your parameters, don't mysql_real_escape_string them; there are security pitfalls there
use password_hash password hashing, not SHA; especially if you're only doing a single SHA pass
becareful SQL Injection :
If you type in password field :
''=''
The password's rule will be true, because Password = TRIM(''='') is true. You have to control the password's string :
Minimum length
No white space (thanks to Trim function)
And you don't have to store a password like this, you must make a password's hash
Will there be any vulnerability if I use a simple LOG IN using IF ELSE statment. I have tried various injections but didnot succeded in any of them, because there is no database/SQL in it. I am using this only for protecting a single page.
$username = $_POST['user'];
$password = $_POST['pass'];
if ($username=='admin' AND $password=='password')
{
echo "<b>Welcome, Admin!</b> You have logged in!";
}
else
{
echo "Sorry! Incorrect Login.";
}
The above code is surely not susceptible to injection attacks as there is nothing to inject any way (like you pointed out).
Things to improve:
Storing passwords in plaintext is generally a really bad idea. Use hash-Values instead.
Password and Username should be sent over encrypted connection (https)
If you are using apache web server use .htaccess file for password protection instead. You'll find many examples on the web
I just wonder what are the best practices to secure a restricted page with PHP.
It has to be really safe.
I guess using the $_SESSION vars is the normal / most secure way.
Here is what I do to log in :
I use a separate sql table with the username and an encrypted password + SALT
SALT is randomly generated and stored in the db (is this a good practice?) at the registration
I use filter_var and PDO on $_POST login and password to avoid sql injection
I check the number of failed logins and set the account inactive after 3 failed attempts
I do not use any cookie
I use SSL
Here is my code if the login is successful, it looks so simple that I'm wondering if it is secure enough :
<?php
// login + password successful
session_start();
$_SESSION['islogged'] = true;
?>
// on each restricted page
<?php
session_start();
if(!$_SESSION['islogged']){
header('Location: unauthorized.php');
exit;
}
// here start my restricted content
?>
I wonder i.e. if using the header function this way is safe enough and 100% reliable?
For the php session security, I already found this interesting content :
What are the risks of PHP sessions?
Is there something else I must be careful of?
Thank you a lot for your suggestions !
I primarily develop HTML/CSS web-pages, and I'm working on a webpage where the users need to have a page password protected from prying eyes. The page would just be for posting non-confidential information, such as private-member events, and scheduling. I know the basics of PHP, and would like to use that, but I'm concerned about safety. The page will have multiple users, but it only needs one password which would be used by all the users. It's also a fairly low-traffic site, so for the situation it doesn't need to be 100% secure, but I would like it to be as secure as possible without too much hassle.
So far I have a login-page that comes up when the user tries to access the member-page, with a password input field, which posts the result to a page called (example name) verifypassword.php
This file looks something like this:
$password = ("mypass");
$passresult = $_POST["password"];
$passresult = strip_tags($passresult);
$passresult = htmlspecialchars($passresult);
if ($passresult != $password) {
die("Invalid password.");
}
elseif ($passresult == &password) {
setcookie("mycookie");
header("location: member-page.php");
}
else {
die("Unknown Error")
}
Then, at the top of the member page, I have some lines of PHP code as follows:
$userloggedin = $_COOKIE["mycookie"];
if (!isset ($userloggedin)) {
die("Please log in to view this page");
}
The files and values themselves are hidden via the die function if the user isn't logged in, but the password and cookie are still being transferred across the server.
I've tried to read up on salting and hashing a password value, but unfamiliar with this kind of thing. How should I be doing this? Are there any tutorials or resources I can read? I tried looking on Google, php.net, and of course here on stackoverflow, but I couldn't find anything that dealt with passwords other than creating a database to store multiple user-generated passwords, which isn't what I need.
I'm currently using WAMPP.
The top line of your code, if you want to follow best practice, should look like this:
$hash = '$2y$10$zRg5l/v9gzD/aICnp/GUlu/rFv/0ZNvxX/A5v86zjepZmuRWWL6IG';
Notice that we're storing a hash instead of the password in plain text. These hashes are generated in the following manner:
password_hash("test", PASSWORD_DEFAULT);
Why are we doing this? Because if your database (or code, in this case) is accessed somehow, then you don't want your passwords to also be stolen. The built in password handling functions mitigate this as much as possible.
In terms of checking the password, you have to make your peace that the user will have to send the password over the internet one way or another! If this is a big concern for you, you can use SSL to mitigate this - it is best practice to always use SSL for at least authentication. This means that if someone intercepts the connection between your user and your website, they will only be able to see encrypted data. Anyway, you would check it as follows when it arrives:
// Assuming single password:
if ( password_verify( $_POST['password'], $hash ) ) {
// correct!
// the plain text in $_POST['password'] is the same as the plain text used to generate $hash
}
Okay, so, next thing. Cookies are sent between the browser and the server as a header. These can be set arbitrarily by the client. So if you rely on a cookie such as $_COOKIE['mycookie'] to authenticate users, then someone could just send a manually-crafted Cookie header to imitate the effect of being logged in. The solution to this particular problem is to use sessions. At the top of every script, you run session_start() which sets its own cookie. This cookie does not contain any information, just a randomly generated unique ID. PHP stores information and associates it to that ID (by means of a file in the temp folder) - but at no point is the client itself able to see what that information actually is - or change it.
To add information to the session you put it in the $_SESSION superglobal as follows:
$_SESSION['logged_in'] = password_verify( $_POST['password'], $hash );
password_verify will return true if the password matched or false otherwise, so you can rely on this to set the boolean properly.
So you can rewrite your code as follows for login.php:
session_start();
$hash = '$2y$10$zRg5l/v9gzD/aICnp/GUlu/rFv/0ZNvxX/A5v86zjepZmuRWWL6IG';
if ( isset($_POST['password']) ) {
// Assuming single password:
if ( password_verify( $_POST['password'], $hash ) ) {
// correct!
header('Location: /member-page.php');
}
}
// display login form
and at the top of the members page:
session_start();
if (empty($_SESSION['logged_in'])) { // checks if it's set and if it's false
die("Please log in to view this page.");
header('Location: /login.php');
}
n.b. I rewrote my answer because I realised it didn't answer many of your questions very well :)
You probably shouldn't be using Cookies to do this since they can be forged on the client side. A session variable will probably work a little better, but if you want to try and keep it simple I would probably MD5 the password with some salt and store it in the cookie, then check that against your MD5ed password + salt when the tries to access the page again.
So off the top of my head something like this:
<?
$password = ("mypass");
$salt = "makeUpASaltHere";
$passresult = $_POST["password"];
$passresult = strip_tags($passresult);
$passresult = htmlspecialchars($passresult);
if ($passresult != $password) {
die("Invalid password.");
}
elseif ($passresult == &password) {
setcookie("mycookie",md5($password.$salt));
header("location: member-page.php");
}
else {
die("Unknown Error")
}
?>
Put this in a separate file and just use require() to include it at the top of all your member pages.
<?
$password = ("mypass");
$salt = "makeUpASaltHere";
$userloggedin = $_COOKIE["mycookie"];
if ($userloggedin == md5($password.$salt)) {
die("Please log in to view this page");
}
?>
Still not as good as using session variables, but at least someone just couldn't just create "mycookie" out of no where and get in. Also it has the advantage that if you ever were to change the password it would automatically log out everyone that was already logged in.