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?).
Related
This is my login page.
include 'config.php';
if (($_POST['username']!=$user) || ($_POST['password']!=$pass))
{
// login deny.
// process usaully terminate at the end of block
}else{
// login grant.
}
$user and $pass value declared in config.php.
Is there any chance that I can login without knowing password and username ?
Like cast $_POST[] to int.
The answer to your question is yes, a user can get through your login without knowing the password. The real question is how hard can you make it for him to do that, and/or how long will it take him to brute force/guess it.
A possible way of preventing brute forcing is to track the number of requests and employing rate-limiting techniques that many API servers use to stop excessive attempts to login. This could use sessions, or better yet an internal log by the client's IP address of the number of attempted requests, and after say 10 failed requests, you lock that IP address out for 24 hours.
A quick-fix solution
Are you going to post your credentials for every page view? You should be only be posting data once, validating it and saving the result to a session variable that you'll then check to determine if the user is logged in.
Here's a short example of a basic, badly secured login system (you should be hashing your passwords!!):
config.php
session_start(); // let's get this puppy rolling
$user = 'example';
$pass = 'anUnsafePasswordHere'; // hash me please!!!
yourpage.php
include 'config.php';
if(!isset($_SESSION['is_logged_in']) || $_SESSION['is_logged_in'] !== true) {
// strict comparison for your login check failed, redirect to login page
header("Location: login.php");
exit;
}
// display regular content here, they are logged in!
Your login page will obviously have a form and will post somewhere, so let's replicate that quickly:
login.php
include 'config.php';
if(isset($_POST['login'])) {
if(
!empty($_POST['user']) // check that the vars exist before trying to
&& !empty($_POST['pass']) // use them in your comparison
&& $_POST['user'] === $user // strict check here, content and var type
&& $_POST['pass'] === $pass
) {
// login succeeded! clear failed validation errors, set success and redirect
unset($_SESSION['login_errors']);
$_SESSION['is_logged_in'] = true;
header("Location: yourpage.php");
exit;
}
// login failed, let's save an error message to the session and redirect back
// to the login form
$_SESSION['login_errors'] = 'Login failed, please try again!';
header("Location: login.php");
exit;
}
?>
<form action="login.php" method="post">
<?php if(!empty($_SESSION['login_errors'])) echo '<p>' . $_SESSION['login_errors'] . '</p>'; ?>
<input type="text" name="user" placeholder="Username">
<input type="password" name="pass" placeholder="Password">
<button type="submit" name="login">Login!</button>
</form>
If you use a basic structure like this for your login system you shouldn't go too far wrong. The idea is that whenever the session variable representing your "logged in" state isn't present, you're forcing a redirect to the login page.
The login page posts to itself, where the credentials are checked and if it's all OK that logged in state session variable is set, and you're send back to the main page - where it does pass the validation check at the top of the page this time.
Obviously to log out, you will just call unset($_SESSION['is_logged_in']); or session_destroy() then redirect back to the login page.
Security notes
Now for security reasons you should definitely implement some hashing.
If you only want one account to access your script and you think using a database purely for this is a little excessive, you can store your credentials in the source code, however you should always store your passwords as hashed representations of what they are so that anyone who happens to look over your shoulder or somehow obtain access to your source code won't immediately see your password.
A couple of old classic (but now phased out due to more secure alternatives) methods of quick, built into PHP hashing techniques are using md5() or sha1() to give a hashed representation of your password. Hashing is a sort of one-way encryption, and it takes a machine a long time to brute-force what a hash represents, so any security is better than none. I suggest you use bcrypt, but a baseline level of security for your application (better than nothing!) would be to use md5() to turn your secretpassword into a hash like 2034f6e32958647fdff75d265b455ebf, then store that in your source code.
All you need to change in your login file is the line that compares the password you've posted with the one in the source code:
if(md5($_POST['pass']) === $user)
To take hashing to a modern best-practice level, you should be looking at using something like bcrypt to store your passwords securely.
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.
if (strtolower($userDetail["username"]) == strtolower($username) &&
$userDetail["password"] == hash("sha256", $password . $userDetail["salt"])) {
if ($remember == "true") { // Remember Me
setcookie("logged", "$username", time()+60*60*24*365); // 1 Year
} else {
setcookie("logged", "$username", time()+43200); // 12 Hours
}
header("Location: " . getenv("HTTP_REFERER"));
die();
} else {
echo "Invalid login.";
}
I'm trying to make the best possible login I possibly can. The major problem I'm seeing here is cookies. I'm no expert when it comes to this, so here are my main questions:
What should I be setting my cookie as so someone can not easily duplicate the cookie?
Should I be including the salt into the cookie?
I've heard about tokens in addition to salts and having them change all the time. How is this supposed to work?
And I'm wondering if this call for my cookie above is even valid? What's the right way to be doing this?
$loginCheck = $_COOKIE["logged"];
if (isset($loginCheck)) {
// logged in
}
I like to leave the username intact, and have another cookie set as sha1(salt . user . pass)
For instance:
user=Truth
uid=6cb8d1e35e5982a8ef738a8583a5d98d6fe2c484
And then compare using the first cookie, against the database and the known hash.
The way you're doing it at the moment, anyone can copy a cookie and log in with anyone without even knowing their passwords. Just set
logged=Admin expires Jan 1st 5000
And you're good to go. Once you have this second cookie to compare against, you're much safer.
As for the third question, yes, you can even shorten it to:
if (isset($_COOKIE["logged"])) {
But as I stated, you should move to the more secure format I've shown.
See this Absolutely EPIC Tutorial on net.tutsplus.com for more on the subject.
I would recommend using a uniqid which is stored on the customer record and then when you validate that the customer has successfully logged in set the cookie with the uniqid from their customer record. This way no one should be able to replicate the cookie. You could also prefix the cookie value with something if you want to ensure it's safe.
I think incorporating the user's password into the cookie is a dangerous idea as people tend to use the same password on other sites and even though it's encrypted in my opinion it's still dangerous. Using a value unrelated to the customer's information I feel is safer.
<?php
/* A uniqid, like: 4b3403665fea6 */
printf("uniqid(): %s\r\n", uniqid());
?>
A reference on how to use uiqid: http://php.net/manual/en/function.uniqid.php
I have a classifieds website which I am creating a login system for...
In the code below, a form with "username" and "password" has been submitted to. Also a "remember_me" feature is available (Code is not tested yet):
else if($row['password']===$pass){
session_start();
$_SESSION['logged_in'] = '1';
$remember_me = isset($_POST['remember']) ? $_POST['remember'] : '0';
if($remember_me=='1'){
$text = "SECRET_TEXT_AND_NUMBERS_HERE";
$username= $row['username'];
$salt1 = sha1($row['alt_username']);
$salt2 = sha1($text);
$cookie_value = $salt1.':'.$username.':'.sha1($row['alt_username'].$salt2.$salt1);
setcookie("s_b", $cookie_value, time()+60*60*24*100, "/");
}
}
Now, is this code a good start for a login page?
Also, an important follow-up question to all this, if users want to stay logged in, do I then set a $_SESSION variable like the one in the code, and just check if that is set in the beginning of all pages on the site?
if(isset($_SESSION['logged_in'])) // Then user is logged in already
or do I check to see if the cookie created in the login page is set instead of checking the session?
logging in is about security; security is always more difficult then it seems.
There are a couple of things that you could improve in your code. first:
the security for your password is in the strength of the hasing algorithm. You choose to use sha1 (better than md5, but could be improved by using sha256 or bCrypt if you use PHP version >= 5.3)
First
The salt you use is supposed to be a random value, stored alongside the hashed result.
in other words, the value to store in your database is:
$salt = [some random string of predifend lenght]; // Let's say 16 characters in length
$storedValue = $salt . sha256($salt . $password);
you check the password:
if ($row['username'] == $_POST['username'] && substr($row['$storedValue'], 16) == sha256(substr($row['$storedValue'], 0, 16) . $_POST['password'])) {
// login ok
} else {
// login fail
}
(better yet)
Use a proven library for the password hashing stuff, take a look at: Portable PHP password hashing framework and try to use the CRYPT_BLOWFISH algorithm if at all popssible.
Second
You should only store the session key in the session cookie. all other information is stored on the server.
The session cookie is already send out by PHP's session_start() function call, so you do not have to worry about this anymore.
if you want to check the sessions lifetime, you should store this information in the session array:
$_SESSION['lastActivity'] = time()+60*60*24*100;
Third
The remember me token is a 'password equivalent' so you should only store a hash of the token in your database, just treat it as a password, only this 'password' is not typed by the user, but read from the cookie.
The whole point of a hash is that its non-reversible, so it's not really adding any value the way you've used for the remember me function. Stop pretending it does anything useful, and use a random token for the remember me (and log this in the database against the username) then, if you get a client presenting a remember me cookie without an authenticated session, you know where to look to find out who it is.
(this also allows a sensible approach to be applied where the user keeps moving to different machines - you might say keep the last 2 values - and flag when they try to remember me from a 3rd machine).
A 100 day timeout is rather long - maybe 30 days (with an automatic refresh might be more appropriate depending on the level of risk.
I have a session that I gave to users that has matching password = stored password, like a simple login system :
// Checks Password and Username
if ($pSys->checkPassword($AccountData['password'], $StoredData['password'])) {
$_SESSION['login'] = true;
}
The question is: is this secure enough?
// put this on every header page that needs to be loggedin.
function loginCheck(){
if ( empty( $_SESSION['login'] )) {
header( 'location:index.php' );
die();
}
}
Is there a difference between die() and exit()? Second, some say that I should add session_regenerate_id()? (Is that an overkill?) Anyway the real question is said above.
addon*
I have read PHP Session Security but it seems it doesn't match my problem here (that link is just to general).
Here is the checkPassword() method
function checkPassword($password, $storedpassword) {
if($password == $storedpassword){
return true;
}
}
Answering the first part: empty and die are not comparable:
empty is to check if a variable does not exists or has a value equal to false (see also this type comparison table).
die is an alias of exit and is used to immediately abort the execution of the current script with an optional message.
Now to your authentication example: Yes, you should use session_regenerate_id to generate a new session ID and revoke the old session ID by setting the optional parameter for session_regenerate_id to true:
if (!sizeof($ErrorAccount)) { // Checks Password and Username
session_regenerate_id(true);
$_SESSION['login'] = true;
}
The purpose of session_regenerate_id is to avoid session fixation attacks. This will not be necessary if the server only allows session ids to be sent via cookies, but since PHP by default allows them in URL, you're strongly recommended to regenerate the id.
Since you are looking for answers about security, also don't keep the stored password in plain text. At the very least, salt and hash your passwords, then store the hash. Rehash and compare hashes, not plain text.
You could added a token (hash) to the form and then validate the token to make sure that the token which was submitted via the form is still valid. This helps to prevent CSRF attacks.
You could also store the IP address and browser together with the token in a database for additional validation, however you need to be aware that some ISP's change the clients IP address fairly often and could cause the validation to fail incorrectly.
More Info