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.
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 am running a simple service where users have to login to be able to operate special functonalities.
My MySQL database stores the username, password and user_id.
When user wants to login, they must provide their username and password which are posted to profile.php.
The profile.php does a simple check:
// Sanity Check
if(empty($_POST['smart_email'])|| empty($_POST['smart_password']))
{
echo 'Sorry, wrong login/passwd';
exit;
}
else
{
//
$smart_email = $_POST['smart_email'];
$smart_password=$_POST['smart_password'];
// Check if registerd and password matches
if(DB_IsAuthorized($smart_email, $smart_password) == true)
{
// Obtain proper UserID from the database
$UserID = DB_GetId($smart_email);
// set the session user_id variable
$_SESSION['user_id'] = $UserID;
//
// Display the User profile page
//
}
}
From that moment, every single page that is user-related has a check for user_id set in $_SESSION to find out if this user was logged in and is authorized.
if (isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']) && $_SESSION['user_id']>0)
{
// USER IS LOGGED IN
}
The question is: Is this $_SESSION['user_id'] check enough to secure the pages from NON LOGGED IN USERS ?
This question is too broad but simple answer is no.
Firstly, you will need https to make sure you protect users from hackers by using firewalls and other required security tools.
Secondly, you need to use htaccess to change extensions, say show user .html instead of .php
Thirdly, Sessions can be hijacked easy by hackers. So always try to store encrypted session values instead of plain text.
There are a lot more issues to take care of but its too complex and broad.
I have some problem understanding how to use php 5.5.0+ password_hash and password_verify to protect pages access.
Let me explain what I did.
1) When I create a new user for my webapp, I store username and hashed password in a users table. To hash the password before to store it in the db, I use
$hashedp = password_hash($password, PASSWORD_DEFAULT);
2) On page login I can take the password submitted by the user in the form and 'compare' it with that stored in the database for the same user in this way
$password = the password submitted by the user
$user_hashedp = the hashed password taken from the db
if (password_verify($password, $user_hashedp)) {
// login the user
} else {
// show error
}
3) What I don't understand is how I can check and protect access to other pages, after the user has logged in. Imagine You have another page page1.php that you want to show only if the user is logged correctly.
How can I build this check?
kind regards,
Matt
Like already said in the comments you can use session for this. Below an example.
session_start();
if (password_verify($password, $user_hashedp)) {
// login the user
// create session for logged in user.
$_SESSION['authorized'] = true;
} else {
$_SESSION['authorized'] = false;
// show error
}
Then in authorizedusersonly.php:
session_start();
if($_SESSION['authorized'] === true) {
//content for authorized users
} else {
//content for unauthorized users
}
I'm not entirely sure how late I am to the party, but Daan has the right idea with doing sessions.
I would personally set a username session variable upon a successful login, then on every page, make sure that it is set. If it isn't, redirect them to a certain page, e.g. a login.
if (password_verify($password, $user_hashedp)) {
$_SESSION["user"] = $user; // user being the login username; also verified.
} else {
echo "Invalid credentials!"; // Throw some type of error. That's up to you.
}
On each page, you can either include a file that will house the session verification code, or just copy/paste it onto every one of your pages, like this:
if (!isset($_SESSION["user"])) // If the user has not been verified...
header("Location: login.php"); // Redirect them to a page of your choice, i.e. a login.
You could do it the other way, but the greatest advantage you'd have with this is the fact that if you ever need to obtain the username for something, instead of having to get the username through a query, which might affect performance, you could simply reference the session variable and deal with it from there.
That is how I would personally do it.
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.
What is the best way to password protect folder using php without a database or user name but using. Basically I have a page that will list contacts for organization and need to password protect that folder without having account for every user . Just one password that gets changes every so often and distributed to the group. I understand that it is not very secure but never the less I would like to know how to do this. In the best way.
It would be nice if the password is remembered for a while once user entered it correctly.
I am doing approximately what David Heggie suggested, except without cookies. It does seem insecure as hell, but it is probably better having a bad password protection then none at all.
This is for internal site where people would have hell of a time remembering their login and password and would never go through sign up process... unless it is really easy they would not use the system at all.
I wanted to see other solutions to this problem.
With user base consisting of not very tech savvy people what are other ways to do this.
Edit: SHA1 is no longer considered secure. Stored password hashes should also be salted. There are now much better solutions to this problem.
You could use something like this:
//access.php
<?php
//put sha1() encrypted password here - example is 'hello'
$password = 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d';
session_start();
if (!isset($_SESSION['loggedIn'])) {
$_SESSION['loggedIn'] = false;
}
if (isset($_POST['password'])) {
if (sha1($_POST['password']) == $password) {
$_SESSION['loggedIn'] = true;
} else {
die ('Incorrect password');
}
}
if (!$_SESSION['loggedIn']): ?>
<html><head><title>Login</title></head>
<body>
<p>You need to login</p>
<form method="post">
Password: <input type="password" name="password"> <br />
<input type="submit" name="submit" value="Login">
</form>
</body>
</html>
<?php
exit();
endif;
?>
Then on each file you want to protect, put at the top:
<?php
require('access.php');
?>
secret text
It isn't a very nice solution, but it might do what you want
Edit
You could add a logout.php page like:
<?php
session_start();
$_SESSION['loggedIn'] = false;
?>
You have logged out
Assuming you're on Apache:
http://httpd.apache.org/docs/1.3/howto/htaccess.html#auth
If you want to avoid cookies, sessions and don't want to play with .htaccess files, you can also do http authentication soley with PHP:
http://www.php.net/manual/en/features.http-auth.php
You can hard code the password into the file and change it as needed, or include it from a file not in your web_accessible directory.
The downside is you don't have the ability to format the "login" screen - it will be a standard http authentication dialog box
I doubt if this would count as the best wasy of doing it, but it would work. And since security doesn't seem to be a big issue for you, the fact that this way's as insecure as hell probably won't bother you either.
Have a login.php page that takes a password and then sets a cookie if the login details are correct. Each php file can then check for the existence of the cookie to determine whether or not the user is "logged in" or not, and display information accordingly.
login.php
...
if(isset($_POST['password']) && $_POST['password'] == 'my_top_secret_word') {
setcookie('loggedin', 'true', time() + 1200, '/url/');
} else {
setcookie('loggedin', 'false', time() - 1200, '/url/');
// display a login form here
}
etc
each "protected" page would then check for this cookie:
if(isset($_COOKIE['loggedin'])) {
if($_COOKIE['loggedin'] == 'true') {
$showHidden = true;
} else {
$showHidden = false;
}
} else {
$showHidden = false;
}
I'm sure you get the (highly insecure) idea ...
Well since you know it's insecure to begin with, you could store a password in a text file somewhere on your web server. When someone accesses the page you could show a form that asks for a password. If the password matches what is in the text file, then you reload the page and display the information. Using the text file will allow you to change the password without having to modify the page they are accessing when you want to change it. You're still going to be sending plaintext everywhere unless you're using SSL. Let me know if you need some code.