PHP Password Hashing API Tutorial

Learn how to use PHP 5.5’s password hashing API to store your user passwords more securely. A simple to use API that helps developers move towards bcrypt.

Are you hashing your user passwords? If not, you’re asking for trouble (just look at the recent password leaks). Keeping plain text passwords or using older, weaker algorithms like MD5 or SHA1 to store passwords have become outdated and less secure than newer, modern methods. For instance, with the release of PHP 5.5, you can use the new password hashing api.

Everybody knows that you should be hashing user passwords using bcrypt, but still a surprising number of developers uses insecure md5 or sha1 hashes. One of the reasons for this is that the crypt() API is ridiculously hard to use and very prone to programming mistakes.

PHP Password Hashing Functions

By adding a new, very simple to use API PHP hopes to move more developers towards bcrypt. It has four simple functions:

  • password_hash() – used to hash the password
  • password_verify() – used to verify a password against its hash
  • password_needs_rehash() – used when a password needs to be rehashed
  • password_get_info() – returns the name of the hashing algorithm and various options used while hashing

How to Hash Passwords Using PHP

Although the crypt() function is secure, it’s considered by many to be too complicated and prone to programmer error. Some developers then use a weak salt and weak algorithm for generating a hash instead, for example:

[code_highlight lang=”php”]$hash = md5($password . $salt); // works, but dangerous[/code_highlight]

But the password_hash() function can simplify our lives and our code can be secure. When you need to hash a password, just feed it to the function and it will return the hash which you can store in your database. Creating password hashes can’t be any simpler than this:

[code_highlight lang=”php”]$hash = password_hash( $password, PASSWORD_DEFAULT );[/code_highlight]

This will create a password hash using the default algorithm (currently bcrypt), the default load factor (currently 10) and an automatically generated salt. The used algorithm and salt will also be part of the resulting hash, so you don’t need to worry about them at all.

If you don’t want to stick with the defaults (which might change in the future), you can also provide algorithm and load factor yourself:

[code_highlight lang=”php”]$hash = password_hash( $password, PASSWORD_BCRYPT, [‘ cost’ => 12 ] );[/code_highlight]

That’s it! The first parameter is the password string that needs to be hashed and the second parameter specifies the algorithm that should be used for generating the hash.

The default algorithm is currently bcrypt, but a stronger algorithm may be added as the default later at some point in the future and may generate a larger string. If you are using PASSWORD_DEFAULT in your projects, be sure to store the hash in a column that’s capacity is beyond 60 characters. Setting the column size to 255 might be a good choice. You could also use PASSWORD_BCRYPT as the second parameter. In this case the result will always be 60 characters long.

The important thing here is that you don’t have to provide a salt value or a cost parameter. The new API will take care of all of that for you. And the salt is part of the hash, so you don’t have to store it separately. If you want to provide your own salt (or cost), you can do so by passing a third argument to the function, an array of options.

[code_highlight lang=”php”]$options = [
‘salt’ => custom_function_for_salt(), //write your own code to generate a suitable salt
‘cost’ => 12 // the default cost is 10
];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);[/code_highlight]

In this way, you are always up-to-date with new security measures. If PHP later decides to implement a more powerful hashing algorithm your code can take advantage of it.

Verifying PHP Hashed Passwords

Now that you have seen how to generate hashes with the new API, let’s see how to verify a password. Remember that you store the hashes in a database, but it’s the plain password that you get when a user logs in.

The password_verify() function takes a plain password and the hashed string as its two arguments. It returns true if the hash matches the specified password. Verifying passwords is just as easy:

[code_highlight lang=”php”]// $password from user, $hash from database
if (password_verify($password, $hash)) {
// password valid!
} else {
// wrong password 🙁
}[/code_highlight]

Just remember that the salt is a part of the hashed password which is why we are not specifying it separately here.

Rehashing PHP Passwords

As time goes by you might want to change the password hashing algorithm or load factor, or PHP may change the defaults to be more secure. In this case new accounts should be created using the new options and existing passwords rehashed on login (you can do this only on login because you need the original password to do a rehash).

Doing this is also very simple:

[code_highlight lang=”php”]function password_verify_with_rehash( $password, $hash ) {
if ( ! password_verify( $password, $hash ) ) {
return false;
}

if ( password_needs_rehash( $hash, PASSWORD_DEFAULT ) ) {
$hash = password_hash( $password, PASSWORD_DEFAULT );

// update hash in database
}

return true;
}[/code_highlight]

The above snippet will keep your hashes up to date with the PHP default. But once again you can also specify custom options, e.g. password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12']).

Retrieve PHP Hashed Password Info

Use password_get_info() to return an associative array with information about the given hash. When passed in a valid hash created by an algorithm supported by password_hash(), this function will return the following:

  • algo – a constant that identifies a particular algorithm
  • algoName – the name of the algorithm used
  • options – various options used while generating the hash

Compatibility for Older PHP Versions

The new API will only be introduced in PHP 5.5. Those who are using PHP 5.3.7 (or later) can use a library called password_compat which emulates the API and automatically disables itself once the PHP version is upgraded to 5.5.


Conclusion

The PHP password hashing API is definitely easier to work with than fumbling with the crypt() function. If your website is currently running on PHP 5.5, then I strongly recommended that you use the new hashing API. Learn more about the PHP password hashing API:

Using a Content Security Policy? You Should Be.

Since the Edward Snowden fiasco, seems like security has been the latest buzz world around the water cooler. From the FBI accessing your webcam, NSA spying on virtual worlds, law enforcement spying on calls, to hackers hijacking commercial drones—doesn’t seem anybody is safe from the prying eyes of Big Brother.

Since the Edward Snowden fiasco, seems like security has been the latest buzz world around the water cooler. From the FBI accessing your webcam, NSA spying on virtual worlds, law enforcement spying on calls, to hackers hijacking commercial drones—doesn’t seem anybody is safe from the prying eyes of Big Brother.

As a web developer, I’m always on the lookout how to make my sites more secure. Recently, I was tasked with implementing a Content Security Policy. I had heard of CSP‘s before, but never really dug deep into them. After doing a little research, I’ve found that their an excellent way to help protect your site from malicious attackers and shady scripts. If you’re not using a Content Security Policy on your site, you should be.

Plug-in-Play Content Security Policy Options

What is a Content Security Policy?

A Content Security Policy is an HTTP response header that helps you reduce XSS risks on modern browsers by declaring what dynamic resources are allowed to load via a HTTP Header.

A CSP adds an extra layer of security that helps to detect and mitigate certain types of attacks, like Cross-site scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. For the laymans, a CSP basically says, ‘Yes, it’s safe to load this file from an external website’, or ‘No, don’t load this file’.

Content Security Policy Browser Support

CSP is designed to be fully backward compatible; browsers that don’t support it sill work with servers that implement it, and vice-versa. If one is implemented and the browser doesn’t support it, it will simply ignore it. Instead, it will default to the standard same-origin policy for web content.

Header Chrome Firefox Safari Internet Explorer
Content-Security-Policy (CSP 1.0) 25+ 23+
X-Content-Security-Policy - 4.0+ - 10+ Limited
X-Webkit-CSP 14+ - 6+ -
Prior to Firefox 23, the X-Content-Security-Policy HTTP header was used. Firefox 23 and later use the now-standard Content-Security-Policy header. During the transition from the previous header to the new header, sites can send both the X-Content-Security-Policy and Content-Security-Policy headers. In this situation, the X-Content-Security-Policy will be ignored and the policy contained in the Content-Security-Policy header will be used.

For more browsers and version support, take a look at caniuse.com/contentsecuritypolicy.

Adding a Content Security Policy

Enabling a CSP is as easy as configuring your web server to return the Content-Security-Policy HTTP header (or browser specific header like Firefox 23 and below's ). You'll need to decide what policies you want to enforce, and then configure them using the CSP header to establish the policy.

Defining Your Policy

You can use the Content-Security-Policy HTTP header to define your policy, where 'policy' is the directive:

Content-Security-Policy: policy

CSPs are made up of one or more directives, multiple directives are separated with a semi-colin ;. Your policy should include a default-src policy directive, which is a fallback for any resource type that you don't explicitly establish.

The Content Security Policy standard specifies that a meta element can be used to configure a policy, but this behavior is not yet supported in Firefox. Support for this feature is being added in bug 663570.

Content Security Policy Examples

Here's some common scenarios that arise when writing your security policy:

A web site administrator wants all content to come from the site's own domain, excluding even subdomains.

Content-Security-Policy: default-src 'self'

A web site administrator wants to allow content from a trusted domain and all its subdomains.

Content-Security-Policy: default-src 'self' *.mydomain.com

A web site administrator wants to allow users of a web application to include images from any domain in their custom content, but to restrict audio or video media to come only from trusted providers, and all scripts only to a specific server that hosts trusted code.

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com

Here, by default, content is only permitted from the document's original host, with the following exceptions:

  • Images may loaded from anywhere (note the "*" wildcard).
  • Media is only allowed from media1.com and media2.com (and not from subdomains of those sites).
  • Executable script is only allowed from userscripts.example.com.

An administrator for an online banking site wants to ensure that all its content is loaded using SSL, in order to prevent attackers from eavesdropping on requests.

Content-Security-Policy: default-src https://onlinebanking.jumbobank.com

An administrator of a web mail site wants to allow HTML in email, as well as images loaded from anywhere, but not JavaScript or other potentially dangerous content.

Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *

Note that this example doesn't specify a script-src; with the example CSP, this site uses the setting specified by the default-src directive, which means that scripts can be loaded only from the originating server.

Testing Your Policy

To ease deployment, CSP can be deployed in "report-only" mode. The policy is not enforced, but any violations are reported to a provided URI. Additionally, a report-only header can be used to test a future revision to a policy without actually deploying it.

You can use the Content-Security-Policy-Report-Only HTTP header to specify your policy, like this:

Content-Security-Policy-Report-Only: policy

If both a Content-Security-Policy-Report-Only header and a Content-Security-Policy header are present in the same response, both policies are honored. The policy specified in Content-Security-Policy headers is enforced while the Content-Security-Policy-Report-Only policy generates reports but is not enforced.

Note that the X-Content-Security-Policy-Report-Only header was used before Firefox 23. If both the X-Content-Security-Policy-Report-Only and Content-Security-Policy-Report-Only are sent, the Content-Security-Policy-Report-Only will be used and the X-Content-Security-Policy-Report-Only will be ignored.

The UserCSP Addon also helps test and develop Content Security Policies for a site.

CSP Directive Reference

Directive Description
default-src The default-src is the default policy for loading content such as JavaScript, Images, CSS, Font's, AJAX requests, Frames, HTML5 Media See the Source List Reference for possible values.
script-src Defines valid sources of JavaScript.
style-src Defines valid sources of stylesheets.
img-src Defines valid sources of images.
connect-src Applies to XMLHttpRequest (AJAX), WebSocket or EventSource. If not allowed the browser emulates a 400 HTTP status code.
font-src Defines valid sources of fonts.
object-src Defines valid sources of plugins, eg object, embed or applet.
media-src Defines valid sources of audio and video, eg HTML5 audio, video elements.
frame-src Defines valid sources for loading frames.
sandbox Enables a sandbox for the requested resource similar to the iframe sandbox attribute. The sandbox applies a same origin policy, prevents popups, plugins and script execution is blocked. You can keep the sandbox value empty to keep all restrictions in place, or add values: allow-forms allow-same-origin allow-scripts, and allow-top-navigation.
report-uri Instructs the browser to POST a reports of policy failures to this URI. You can also append -Report-Only to the HTTP header name to instruct the browser to only send reports (does not block anything).

CSP Source List Reference

All of the directives that end with -src support similar values known as a source list. Multiple source list values can be space seperated with the exception of * and none which should be the only value.

Source Value Description
* Wildcard, allows anything.
'none' Prevents loading resources from any source.
'self' Allows loading resources from the same origin (same scheme, host and port).
data Allows loading resources via the data scheme (eg Base64 encoded images).
domain.example.com Allows loading resources from the specified domain name.
*.example.com Allows loading resources from the any subdomain under example.com.
https://img.example.com Allows loading resources only over HTTPS matching the given domain.
https: Allows loading resources only over HTTPS on any domain.
'unsafe-inline' Allows use of inline source elements such as style attribute, onclick, or script tag bodies (depends on the context of the source it is applied to)
'unsafe-eval' Allows unsafe dynamic code evaluation such as JavaScript eval()

See also: