53

What are the best current libraries/methods to authenticate users without the use of a CMS or heavy framework?

Responses should include suggestions for anything you think should be considered the standard for new PHP development involving user authentication.

Kevin Peno
  • 9,107
  • 1
  • 33
  • 56
Daren Schwenke
  • 5,428
  • 3
  • 29
  • 34
  • 2
    Feel free to kick of the list with what you know as a community wiki and we can add to it. – John Paulett Oct 26 '09 at 13:42
  • 1
    You may want to take a look at https://github.com/delight-im/PHP-Auth which is both framework-agnostic and database-agnostic. – caw Sep 21 '16 at 05:10

8 Answers8

29

OpenID is a method to authenticate users based on their existing accounts on common web services such as Yahoo, Google and Flickr.

Logins to your site are based on a successful login to the remote site.

You do not need to store sensitive user information or use SSL to secure user logins.

A current PHP version of the library can be found here.

Daren Schwenke
  • 5,428
  • 3
  • 29
  • 34
  • definately the way to go, completely nixes the need to store any password, so you won't ever be responsible for losing it either. – Kris Nov 09 '09 at 14:38
  • 1
    **OpenID** is *definitely* gaining traction as individuals are realizing the difficulty of maintaining a plethora of user accounts across many domains. It is up to us as developers to *herd the sheep* (typical web users) and provide them easier means for connecting to our websites and improve user productivity. Gone will be the days of forgotten passwords. – Corey Ballou Nov 09 '09 at 18:41
  • 1
    As downfalls of open ID is that not many people know what is OpenID, and might have doubts on entering their mailbox account details as they might asume that your website is tupical fishing website. So as solution I would advise to use OpenID together with internal registration system. – Nazariy Nov 09 '09 at 21:25
  • 1
    Very interesting but this means that everyone can use (if registered)? I'd like to give access to just the users I choose... – Pitto Jun 21 '13 at 08:59
  • 2
    The REAL downfall of openID is that it basically enables any big site operator (google etc) to keep tracking their users and what they do even in your own site. And, your user data depends on that remote provider - not something good. If they decide to effect any change to the openid service they are running, you'll be their ..... – unity100 May 29 '14 at 16:39
  • Another weakness of OpenID, and other similar systems, is that if one account is compromised, an attacker can quickly get access to all of the sites using the login. A lot of damage can be done relatively quickly, even compared to the scenario where the user had different login credentials for each site. – cazort Sep 15 '21 at 19:17
17

Implementing user authentication securely without relying on a framework (or third-party library, such as OpenID) to do it for you is not a trivial undertaking.

At a 10,000 foot overview, you have to decide:

  • Do you have usernames, email addresses, or user IDs as a primary selector?
  • How should you store passwords? PROTIP: password_hash() or scrypt are the way to go.
  • How should you handle "remember me" checkboxes? There are a lot of bad strategies for this on the Internet. Treat every one of them with skepticism, because they might introduce vulnerabilities into your application.
  • How should the application handle users who forget their password?

The information in this answer is relevant and up-to-date as of May 9, 2015 and might be obsoleted by the conclusion of the password hashing competition

Primary Selectors

In general, usernames and email addresses are better than ID numbers.

There should be no security requirement to keep usernames secret, because in practice they will be leaked when someone tries to register anyway.

You can decide whether or not to treat email addresses as a secret. Users generally like not being exposed to spammers, scammers, and trolls.

Password Hashing

You should use password_hash() and password_verify() unless you are sufficiently experienced with writing cryptography libraries to go above and beyond.

Beyond Bcrypt

Sometimes developers like to get creative (e.g. adding a "pepper", which usually means pre-hashing or HMACing passwords with a static key) and go beyond the standard implementations. We ourselves have done this, but very conservatively.

For our internal projects (which have a much higher margin of security than most people's blogs), we wrote a wrapper around this API called PasswordLock that first hashes a password with sha256, then base64 encodes the raw hash output, then passes this base64-encoded hash to password_hash(), and finally encrypts the bcrypt hash with a properly-implemented encryption library.

To reiterate, instead of peppering, we encrypt our password hashes. This gives us more agility in case of a leak (we can decrypt then re-encrypt because we know the key). Additionally, we can run our webserver and database on separate hardware in the same datacenter to mitigate the impact of a SQL injection vulnerability. (In order to start cracking hashes, you need the AES key. You can't get it from the database, even if you escape to the filesystem.)

// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);

// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
    // Authenticated!
}

Password Storage with PasswordLock:

  1. hash('sha256', $password, true);
  2. base64_encode($step1);
  3. password_hash($step2, PASSWORD_DEFAULT);
  4. Crypto::encrypt($step3, $secretKey);

Password Verification with PasswordLock:

  1. Crypto::decrypt($ciphertext, $secretKey);
  2. hash('sha256', $password, true);
  3. base64_encode($step2);
  4. password_verify($step3, $step1);

Further Reading

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
11

I use OpenID .

But like stackoverflow I use the Google project openid-selector to do the heavy lifting.
Demo Page here.

The obvious advantages (of OpenID) are.

  • You don't need to be a security expert.
  • Users trust the big sites with their info.
  • You can request things like (nickname etc) but user has to opt in.
  • You don't need to worry about:
    • registration processes
    • lost/forgotten password
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I like this selector project and have used it before as well. I would suggest that you merge this information with the highly voted answer regarding openid. – Kevin Peno Nov 04 '09 at 07:04
9

A lot of great answers here, but I feel like it's worth saying this--do NOT try to re-invent the wheel in this case! It is extremely easy to screw up user authentication in a wide variety of ways. Unless you really need a custom solution, and have a firm knowledge of security schemes and best practices, you will almost certainly have security flaws.

OpenID is great, or if you're going to roll your own, at least use an established library and follow the documentation!

DougW
  • 28,776
  • 18
  • 79
  • 107
8

PHPass is a lightweight, variable cost password hashing library using bcrypt.

Variable cost means that you can later turn up the 'cost' of hashing passwords to seamlessly increase security without having to invalidate your previously hashed user passwords.

The field size used for hash storage is constant even when increasing 'cost' due to increasing not the size of the hash, but the number of iterations required to produce it.

Daren Schwenke
  • 5,428
  • 3
  • 29
  • 34
  • 55
    I hope that's supposed to be pronounced PHP *pass*. :) – Doug T. Oct 26 '09 at 13:49
  • That's just a simple hashing library, right? Not something that can be used as an authentication system like the OP is asking for. – Camden S. Dec 20 '13 at 00:42
  • 1
    @DougT. No it's not : [`phpass (pronounced "pH pass")`](http://www.openwall.com/phpass/)... :( – Maen Apr 04 '15 at 08:57
  • @ Camden S But others developers also there like me who have related questions and yah this answer helped me rather than top voted OPEN ID because may be the user doesn't have account on services like Facebook,GOOGLE or other top players – Ravinder Payal Oct 04 '15 at 10:27
5

Login using HTTP AUTH

  1. Using Apache: http://httpd.apache.org/docs/2.2/howto/auth.html
  2. It is also possible with IIS and other web servers.

Once authenticated, for PHP, you just have to use $_SERVER['PHP_AUTH_USER'] to retrieve the username used during authentication.

This can be a faster and, sometimes, more flexible solution than handling the solution at scripting level provided that limited information is needed regarding the user as all that is made available to you is the username used to login.

However, forget about integrating your authentication in an HTML form unless you implement a full HTTP AUTH scheme from within your scripting language (as described below).

Rolling your own HTTP AUTH within your scripting language

You can actually extend HTTP Basic Auth by emulating it in your scripting language. The only requirement for this is that your scripting language must be able to send HTTP headers to the HTTP client. A detailed explaination on how to accomplish this using PHP can be found here: (see more on PHP and HTTP AUTH).

You can expand on the article above using a typical authentication schema, file store, even PHP sessions or cookies (if information isn't needed to be persistent), giving you much more flexibility when using HTTP AUTH, yet still maintaining some simplicity.

Downsides to HTTP AUTH

  1. The main downside to HTTP auth is the complications that logging out can have. The main way to clear the user's session is to close the browser, or pass off a header with 403 Authentication Required. Unfortunately, this means the HTTP AUTH popup comes back on the page and then requires users to either log back in or hit cancel. This may not work well when taking usability into consideration, but can be worked around with some interesting results (ie. using a combination of cookies and HTTP AUTH to store state).

  2. HTTP AUTH popups, session, and HTTP header handling is determined by browser implementation of the standard. This means that you will be stuck with that implementation (including any bugs) without the possibility of workaround (unlike other alternatives).

  3. Basic auth also means auth_user and password show up in server logs, and then you have to use https for everything because otherwise username and password also go over the network on every query in plain text.

Kevin Peno
  • 9,107
  • 1
  • 33
  • 56
Patrick Allaert
  • 1,751
  • 18
  • 44
  • Can you explain when this would be more flexible than a php'n'database auth method? – Strae Nov 03 '09 at 16:31
  • 1
    Basic auth also means auth_user and password show up in server logs, and then you have to use https for everything because otherwise username and password also go over the network on every query in plain text. – Daren Schwenke Nov 04 '09 at 00:18
  • @Daniel: I don't know if I would say it is more flexible, but I would argue that its one less interface that needs to be developed, meaning faster implementation. – Kevin Peno Nov 04 '09 at 07:02
  • Sure, but in many web-app the login (and users management) aren't just a 'interface that needs to be developed', used just to login in the app. Often the login and everything is user-relates is the core of the web-app, by it depends users permissions and roles (what he can or cant do), so, if the web-app is php-based, (imho) the more flexible auth method is a php-based one ;) – Strae Nov 04 '09 at 08:52
  • @Daniel: Not if using option 2 (rolling your own) specified above. You can handle permbits, etc just like you do, and use the built in HTTP AUTH modal for handling login requests. – Kevin Peno Nov 04 '09 at 20:30
  • 2
    I'd add that while it's totally ok to use http-auth for internal stuff, it feels very "cheesy"/cheap for the end user if your nice-cool-awesome website uses it. That kind of "perception" problem is hard to solve. – Carlos Lima Nov 09 '09 at 04:41
  • Don't do this. This is a bad, no-longer-standard way of doing things that does NOT gel with current best practices. In particular, the lack of logout control and the plaintext passwords are a serious problem. It's far too clever for it's own good. – Paul McMillan Nov 10 '09 at 01:49
  • Your passwords are transfered in plain text using any other type of form. What's the difference? If you have issues with plaintext passwords and think THIS is the only one that is a risk, you have other things to worry about. I would agree that it is cheesy and cheap for front facing stuff and also wouldn't advise it in that case. – Kevin Peno Nov 10 '09 at 05:08
5

It's important to separate the security layer of your application from the rest of it. If there's no distance between your application logic and your communication system, you are free to communicate insecurely in one place and securely somewhere else. Maybe you'll make a mistake and send a password in an unencrypted cookie, or maybe you'll forget to verify the user's credentials for one step. Without a 'right way' to communicate with the user, you're sure to make a mistake.

For example, let's say this is how you verify users now:

user_cookie = getSecureCookie()
if (user_cookie.password == session_user.password) {
    do_secure_thing()
    ...
}

If a vulnerability is discovered in getSecureCookie(), and you use this code to verify users throughout your application, you might not find all the instances of getSecureCookie() that need to be fixed. If, however, you separate your logic from your security:

if (userVerified()) {
    do_secure_thing()
    ...
}

... you will be able to quickly and easily re-secure your application. Give yourself a 'right way' to do security, and you will be far less likely to make a major security blunder.

Evan Kroske
  • 4,506
  • 12
  • 40
  • 59
1

Best authentication is to utilize multi-factor authentication, ideally a token-less version on all security sensitive log-ons.

Password protected and easier to use with high reliability and security. There are several available beyond EMC/RSA. I prefer SwivelSecure's PINSafe.

Igor S

TheAlbear
  • 5,507
  • 8
  • 51
  • 84
Igor Sill
  • 1
  • 1