2

I have created a small script for work. It's an internal web script but has to be hosted on our public domain so I have created a very small PHP based login system using a login form and a session check. Instead of having to define the password in plain text, can someone show me how to add the password in an encrypted format, without the use of a database or external file?

My login code is posted at the bottom - just above it is the line that I would like to change this password to some kind of encryption so that it cannot be read plaintext should someone gain access to the files, or PHP screws up and starts printing in plain text. I have tried googling and searching SE bu everything is relating to DBs and external conf files.

$logins = array('username' => 'password123');

    <?php session_start();

if(isset($_POST['Submit'])){
$logins = array('username' => 'password123');


$Username = isset($_POST['Username']) ? $_POST['Username'] : '';
$Password = isset($_POST['Password']) ? $_POST['Password'] : '';


if (isset($logins[$Username]) && $logins[$Username] == $Password){


$_SESSION['UserData']['Username']=$logins[$Username];
  if (isset($_SESSION["login_redirect"])) {
        header("Location: " . $_SESSION["login_redirect"]);
        unset($_SESSION["login_redirect"]);
    } else {
        header("Location: index.php");
    }
exit;
} else {

/* Login failed display message */
$msg="<span style='color:red'>Invalid Login Details</span>";
}
}

Thanks for any and all help!

p.s. The script is hosted/served from HTTPS and HTTP2 on PHP 7x and apache in case it makes any difference.

Edit:

To start with there is only 1 user and password. there may be additional users in the future. But as it stands now just one is needed for the staff. There is no requirement for logging user actions etc at the moment.

The script will be on a subdomain of a public website which has its own WAF that also protects the sub dir, so things like brute force will be picked up. We also have Mod Security and CSF on the server which will also help out.

The script is being hosted on the public side as the company does not utilize an internal intranet, VPN or LDAP / AD server etc. The script needs to also be accessible outside the office - should the boss decide to work from home or Starbucks...

I only want to secure the password part because it is stored in plaintext inside the login.php file. If someone was to access it on the server or via FTP etc, they would have easy access to the password. And as mentioned should PHP break I do not want to password shown as plaintext on screen either.

So to update my question a little. Can someone give me starting pointers for replacing the password with a hashed password system instead?

Again I understand a number of people on here will suggest using corporate intranets, VPNs, dedicated platforms blah blah, please understand this is a small company and an even smaller project. Things like staff leaking passwords are less of a worry. I am more interested in securing the password that is already in place and keeping the script as small and as light as possible.

  • 1
    From whom are you protecting the hard-coded password (the 'password123')? I assume it is on the backend? You want to not let other devs see the password? In that case you could read it from one of your environmental variables instead of hard coding it. – hft Sep 7 '18 at 16:30
  • 1
    I'm really just repeating @hft, but none of this is really answerable without more details about what you are trying to secure and from whom. How many people are going to be logging into this? Are you going to have to change the password everytime an employee who had access leaves? Is it protecting valuable internal information, or employee data? – Conor Mancone Sep 7 '18 at 16:57
  • @hft the password is to be protected from everyone. I am not wanting it to be viewed if someone was to download the file and edit it. I also want it hidden to make sure that if PHP breaks on the server and outputs the php files as plain text that it DOES NOT print out the password ! - I don't really follow what you mean about reading from env variable. – Greg Sep 11 '18 at 15:19
  • @ConorMancone It is being secured from outsiders basically. The general population of the internet and a particular software company who are the reason I had to create our script. The script itself is fairly simple. You paste a full URL to a particular cloud resource. It strips the URL rebuilds its and then combines it with iframe code to create a snippet that can be copied to our internal portal and used to embed the cloud resource. But as it will be on a public facing domain I want to ensure maximum protection and make sure passwords are secure. Passwords will be changed when required – Greg Sep 11 '18 at 15:24
3

A few points:

  • Passwords should be hashed, not encrypted. Encryption is reversible; somebody who shouldn't have access but can see the app's source code can find the encrypted password and its encryption key, decrypt the password, and thereby gain access. Hashes are one-way; you can't turn a hash digest back into the text that was hashed.
    • You'll ideally want a slow hash function (PBKDF2, bcrypt, scrypt, or argon2, in order of increasing security) because fast hashes can be brute-forced pretty easily with modern hardware.
    • You'll definitely want to use a salted hash (the algorithms above will expect or auto-generate a salt), as otherwise an attacker can use a rainbow table (or simply Google the hash digest) to find the password very quickly.
  • The system you describe is far too fragile. With every user of this system sharing one password, it will get leaked. Somebody will leave the company, or sign in from a compromised system, or leave it on a sticky note where they shouldn't, or send it over an insecure communication channel, or something. In other words, there's no very secure way to do what you're asking. You really should have per-user access control, and yes, that probably means a database.
    • You also lose meaningful logging ability when you don't differentiate between users. If somebody gets in and abuses the system, you can't know who did it because all logins look the same. Of course, in the snippet above, you don't have any logging at all...
  • You don't mention any kind of password brute-forcing protection, without which an external attacker can probably crack the password in, at worst, a few days of attempts.

There are correct ways to handle your scenario, but they all work differently than you're describing.

  1. Restrict the internal site to intranet (corporate network) IP addresses, and require external users to be on a VPN.
  2. Delegate authentication to your internal login authority. If you have an LDAP/Active Directory server, you can pass the authentication request through to it. In fact, if you use Active Directory and IIS (probably not, since PHP, but still), this is as simple as setting the app to require "Windows Authentication".
  3. Delegate authentication to an external provider, if you use one. For example, if your company uses Google Suite, you can use Google SSO (Single Sign-On) and verify that the user has a company email address. You could also use an external authentication provider, such as Auth0.
  4. I guarantee that it doesn't need to be hosted on your public domain, although without knowing why you think so I can't offer better approaches. Still, this scenario is exactly what intranet servers exist for, and they can talk to your public web server over back-end channels (or via CORS through the client) if needed.

More generally, the fact that you're asking this indicates that you probably shouldn't be trying to roll your own authentication system. Without knowing more about the scenario, I can't say exactly what the risks are, but I would be very surprised if you manage to account for them all with a system like this one. Security is hard; it's a much better idea to go with a proven system developed by people who know what they're doing.

  • Thanks for the lengthy answer. In short, the system is not a mission critical system. Nor does it actually store any particularly valuable data. If it actually held sensitive information I'd probably be using a prebuilt platform like wordpress or something else. However its just a lightweight script in the directory I want to protect without plain text passwords :) So from the sounds of it I need to hash the password and use that instead. Thanks. Its for a small Company, we dont use VPNs or AD servers. So it goes on the domain so that we can access outside of the office if working remotely – Greg Sep 11 '18 at 15:28
  • The other security implications are not really a concern either. It's just me wanting to secure my little script. To most it would be useless anyway.If I'm honest the most valuable data for someone to steal probably IS the password. – Greg Sep 11 '18 at 15:56
1

What/How?

Use password_hash. Copy the returned string value and paste it into the source. Use password_verify to test if the password is correct.

password_hash's algorithm can be PASSWORD_DEFAULT. Increasing the cost parameter of bcrypt is probably a good idea. Argon2 is better if the cost parameters are tuned right, but I don't know if the defaults are good or not.

password_verify takes the password supplied to the login form as its first argument and a string returned by password_hash for its second.

Why?

This is called password hashing. (Not encryption.) Password hash algorithms are a variation on cryptographic hash functions. They are one way processes. You can't recover the user's password without first guessing it correctly. It is still up to the password-creator to choose a strong password.

In offline password cracking, the cracker can try candidate passwords one after the other, doing work equivalent to what password_verify does, until they find a match. (Offline cracking is when someone steals a password hash and attempts to verify it on their own computer, bypassing things your server might do like rate-limiting.)

Password hash algorithms try to accommodate less strong passwords by forcing anyone who wants to test a password to do more work per guess, whether legitimate or illegitimate.

What else?

You should still implement rate-limiting. Maybe temporary account lockouts too. IP address white-listing would also be a good idea, but that might cause usability problems in some situations. White-listing is not foolproof defense either.

To do lockouts and rate-limiting you need some type of read/write store. Session variables wouldn't work because an attacker could just start a new session. Perhaps reconsider your requirements for this reason. Or find another storage like a read/write file outside the document root or key-value store.

To hide the password hashes from someone with access to PHP source, the simplest read-only method I've heard of is to use SetEnv or fastcgi_param but that probably counts as "external conf files".

Hiding the hashes, if it worked, would make it harder to steal password hashes. If they can't get the hashes they can't use offline cracking. However I don't think it will be much help. Maybe you're not hacked yet. Maybe someone hacked your server and has a lot more access than just the ability to read PHP source. It's possible someone only has read access to PHP source, but that really shouldn't be likely. I think your effort is better spent avoiding bugs or misconfigurations to prevent PHP source leaks from happening in the first place.

  • Thanks for the answer. Password Hashing seems to be what I Am wanting. So I need to figure out the best way of implementing this. My next bit of research I guess. I'm not so worried about password cracking, or someone actively trying to break into the script. I just want to have a decent level of basic security without easily giving the password away or displaying it as plain text due to an error or something. – Greg Sep 11 '18 at 15:36
1

Ask a bunch of security people how much security you need and they'll tell you "lots".

Yes, keeping the password in clear text as you are doing is a bad idea. Keeping the password hard-coded in your program is a bad idea.

As @FutureSecurity says, PHP has a useful function password_hash which abstracts away all the complexities of dealing with passwords (you don't just hash a password, which you do with sha1() or md5(), you should add a salt and other things too).

But what do you want here? If its to learn how to be a better programmer, then go read up on using password_hash() but if you just want to apply some secure access control, then you may be better using Apache's auth mechanisms.

  • I know plenty about security and what I need in place hence asking for help to implement. I was just asking for help with the actual programming of it in regards to securing the password not do I need to. I know I need to. PHP is not my strong point. I also decided against basic auth via apache. I prefer having an integrated login form. - Yes it seems I need to learn more about password_hash() but if someone was able to give me a quick start guide that would also be great – Greg Sep 12 '18 at 11:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.