File/program/lib/loginlib.php

Description

/program/lib/loginlib.php -- functions to handle user login/logout

Visitors need to authenticate when they want to see a 'protected' area or when they want to modify the website content. This requires a user account and the visitor presenting valid credentials (username + password).

We don't want malicious scripts trying to get in with brute force. However, we need to accomodate users that make typo's while entering credentials. Also we want to allow for sending password reminders, in a safe way.

Features:

  • users are allowed N login attempts within an interval of T1 minutes
  • users can request a new password (a 'bypass') to be mailed to them. this additional password is valid for only T2 minutes
  • if a user has requested a bypass, the user is forced to change her password. the new password must differ from the old password and also from the bypass
  • if too many failures are detected in the last T1 minutes, login attempts from the corresponding IP-address are blocked for T3 minutes
N = $CFG->login_max_failures, default 10

T1 = $CFG->login_failures_interval, default 12 minutes

T2 = $CFG->login_bypass_interval, default 30 minutes

T3 = $CFG->login_blacklist_interval, default 8 minutes

Once a user is authenticated, a PHP-session is established, using our own database based session handler. The session key is stored in a cookie in the user's browser. Presenting this cookie on subsequent calls is enough to gain access. The logout routine takes care of killing both the user's cookie and the session in the database.

There are several different login procedures.

  1. Normal login The user enters a valid username and password and is subsequently logged in.
2. Change password The user enters a valid username and password and also a valid new password (twice). A salted hash of the new password is recorded in the database and the user is logged in.

3. Forgotten password, phase 1: sending a laissez-passer The user presents a valid combination of username and email address. Subsequently a one-time logon-code (dubbed 'laissez-passer') is sent to the user's email address. This code is valid for at most T2 minutes. This code can be used, exactly once, to send a temporary password via email.

4. Forgotten password, phase 2: sending a temporary password The user clicks the link received in phase 1 and a temporary password (dubbed 'bypass') is sent to the user. This temporary password is valid for another T2 minutes.

5. Message box This is a pseudo-procedure. A simple 'message box' type of screen is displayed but no real interaction is anticipated via this screen. This is used to tell the user that things didnt work out (too many failures) or to check their mail for further instructions (e.g. when a laissez passer was sent). Whenever the user acknowledges this screen by clicking the button, she usually is directed to $WAS_SCRIPT_NAME.

6. Blacklist This is also a pseudo-procedure. The corresponding number is used to identify blacklisted IP-addresses in the database.

Note that when the user logs in after a temporary password has been sent, the normal login procedure is immediately followed by a (forced) 'change password' procedure. This makes sure that a temporary password will be changed immediately after the user logs in.

Note that each of the procedures can be entered 'manually', i.e. by opening index.php?login=X the user starts procedure X. This allows for the user to change her password whenever she feels this is necessary, without going through the trouble of the 'forgotten password'-procedure which eventually ends with the user changing her password too.

  • author: Peter Fokker <peter@berestijn.nl>
  • version: $Id: loginlib.php,v 1.19 2016/03/23 09:28:34 peter Exp $
  • copyright: Copyright (C) 2008-2016 Ingenieursbureau PSD/Peter Fokker
  • todo: should we suppress the username in the laissez-passer routine? We _do_ leak the the username in an insecure email message. This does require making the laissez-passer code unique in the database (currently only username+code has to be unique and that's easy because the username itself is unique).
  • todo: should we normalize the remote_addr everywhere? We now rely on the remote_addr being equal to some stored value (in the database) but with an IPv6 address there are several possibilities to have different representations of the same address (e.g. '::dead:beef' is equivalent to ::0:dead:beef' or even '::DeAd:BeeF' or '0000:0000:0000:0000:0000:0000:DEAD:BEEF'. This problem also exists with IPv4: '127.0.0.1' is equivalent to '127.000.000.001'. *sigh*
  • usedby: mypage_view_password()
  • usedby: admin_show_login_and_exit()
  • usedby: admin_login()
  • usedby: admin_logout_and_exit()
  • license: GNU AGPLv3+Additional Terms
Constants
BY_EMAIL = 2 (line 156)

this selects authentication via username+email in authenticate_user()

BY_LAISSEZ_PASSER = 3 (line 159)

this selects authentication via username+laissez_passer in authenticate_user()

BY_PASSWORD = 1 (line 153)

this selects authentication via username+password in authenticate_user()

LOGIN_FAILURE_DELAY_SECONDS = 3 (line 138)

this is the number of seconds to delay responding after a login action fails (slow 'm down..)

LOGIN_PROCEDURE_BLACKLIST = 6 (line 135)

this is a pseudo procedure, used to record blacklisted IP-addresses

LOGIN_PROCEDURE_CHANGE_PASSWORD = 2 (line 123)

this is the procedure to change the user's password

LOGIN_PROCEDURE_MESSAGE_BOX = 5 (line 132)

this is a pseudo procedure, used to deliver some message to the user

LOGIN_PROCEDURE_NORMAL = 1 (line 120)

this is the usual procedure for logging in

LOGIN_PROCEDURE_SEND_BYPASS = 4 (line 129)

this is phase 2 of the 'forgot password' procedure

LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER = 3 (line 126)

this is phase 1 of the 'forgot password' procedure

LOGIN_PROCEDURE_SHOWLOGIN = 0 (line 117)

this only shows the login dialog

MINIMUM_PASSWORD_DIGITS = 1 (line 150)

this is the hardcoded minimal number of digits in a new password

MINIMUM_PASSWORD_LENGTH = 6 (line 141)

this hardcoded minimal length is enforced whenever a user wants to change her password

MINIMUM_PASSWORD_LOWERCASE = 1 (line 144)

this is the hardcoded minimal number of lower case characters in a new password

MINIMUM_PASSWORD_UPPERCASE = 1 (line 147)

this is the hardcoded minimal number of upper case characters in a new password

Functions
acceptable_new_password (line 1090)

check the new passwords satisfy password requirements

Users should provide the same password twice, to prevent typo's, so both passwords should be equal. Also, the following requirements should be satisfied:

  • the minimum password length should be MINIMUM_PASSWORD_LENGTH (default 6)
  • the new password should contain at least MINIMUM_PASSWORD_LOWERCASE lowercase letter a-z (default 1)
  • the new password should contain at least MINIMUM_PASSWORD_UPPERCASE upper case letter A-Z (default 1)
  • the new password should contain at least MINIMUM_PASSWORD_DIGITS digit 0-9 (default 1)
  • the new password should not be the same as the previous password
  • the new password should not be the same as the bypass password (if any was issued)
Note that the bypass-generator also should satisfy these rules. This could lead to the thought of accepting the bypass-password as the permanent one. However, since this temporary password was sent to the user in a plain-text email message, we should consider this a 'bad' password.

The minimum password length and other minimum values are not configurable (via $CFG) because that would make it too easy (too tempting) to give in and use weak passwords (too short, only lowercase, etc.) However, if your really MUST, you could change the MINIMUM_PASSWORD_* constants defined above.

Note that the check agains existing (temporary and regular) passwords is not performed if the corresponding parameters are empty. If they are empty, this routine only performs the first 4 checks in the list above.

  • return: TRUE if new password is acceptable, FALSE otherwise
  • todo: Entropy! Perhaps it is better to value the strength of a password in a different way, say 'CorrectHorseBatteryStaple' could be better than 'Tr0ub4dor&3'. Also, why force a limited set of ASCII-characters [0-9A-Za-z] when there is so much entropy to gain by using characters in the range U+0080 - U+10FFFF? (20140912/PF)
  • usedby: mypage_authorisation()
  • usedby: mypage_password_dialog_validate()
bool acceptable_new_password (string $new_pass1, string $new_pass2, [string $salt = ''], [string $password_hash = ''], [string $bypass_hash = ''])
  • string $new_pass1: new password
  • string $new_pass2: new password again, to prevent typo's
  • string $salt: (optional) the salt that was used to hash the old password and the bypass
  • string $password_hash: (optional) the hashed existing password
  • string $bypass_hash: (optional) the hashed bypass password
authenticate_user (line 982)

check the user's credentials in one of three ways

This authenticates the user's credentials. There are some variants:

  • by password: the user's password should match
  • by email: the user's email should match
  • by laissez passer: the one-time authentication code should match
Strategy: we first read the active record for user $username in core. If there is none, the user does not exist or is inactive => return FALSE.

After that we check the validity of the token:

  • a password is checked via the password hash or, if that fails, via the bypass hash. In the latter case, the bypass should not yet be expired (a bypass and a laissez_passer are valid until the 'bypass_expiry' time).
  • an email address is checked caseINsensitive and without leading/trailing spaces
  • a laissez_passer is check much the same way as the bypass password, be it that the code is stored 'as-is' rather than as a hash. The comparison is caseINsensitive.
If the credentials are considered valid, an array with the user record is returned, otherwise FALSE is returned.

Because there are actually several checks to be done, we decided not to use SQL like: SELECT * FROM users WHERE username=$username AND password=$password, not the least because we need to have the salt in our hands before we can successfully compare password hashes.

Note: The 'special cases' (checking email, checking laissez_passer, checking bypass) all have their token stripped from leading and trailing spaces. We don't want to further confuse the user by not accepting a spurious space that was entered in the heat of the moment when the user has 'lost' her password. Therefore we also always trim the username. Rationale: usernames and also the generated passwords etc. never have leading/trailing spaces. However, one cannot be sure that a user has not entered a real password with leading/trailing space, so we do NOT trim the $token in the first attempt in the case 'BY_PASSWORD' below.

bool|array authenticate_user (int $by_what_token, string $username, string $token)
  • int $by_what_token: which authentication token to use
  • string $username: username the user entered in the dialog
  • string $token: the token is either password, email or laissez_passer entered by the user
login_change_password (line 1034)

update the users database with a new (randomly salted) password and reset bypass mode to normal

This updates the user record for user with user_id and stores the new password. The new password and a new random salt are hashed together and the result is stored, together with the new salt, overwriting the old salt and the old password hash. The bypass mode is reset to normal and the bypass hash is reset. Return TRUE on success.

bool login_change_password (int $user_id, string $new_password)
  • int $user_id: identify the user record by user_id
  • string $new_password: the new password in plain text
login_dialogdef (line 1380)

construct a standard dialog definition for a specific login procedure

There are 5 different dialogs, each with 1, 3 or 5 inputs, depending on $dialog

Field                   Used in dialogs:
login_username          1 2 3 4
login_password          1 2
login_new_password1       2
login_new_password2       2
login_email                 3
login_laissez_passer          4
button                  1 2 3 4 5

Note: There is some discussion about the autocomplete flag. Before HTML5 it was a browser-specific feature that sometimes didn't work. However, we can at least try to prevent it by adding autocomplete="off" to password fields.

  • return: ready to use dialogdef
array login_dialogdef (int $dialog)
  • int $dialog: indicates which dialog to construct
login_failure_blacklist_address (line 1256)

add remote_addr to the blacklist for specified interval (in seconds)

bool|int login_failure_blacklist_address (string $remote_addr, int $delay_in_seconds, [string $username = ''])
  • string $remote_addr: the remote IP-address is the origin of the failure
  • int $delay_in_seconds: the number of seconds to put this address on the blacklist
  • string $username: extra information, could be useful for troubleshooting afterwards
login_failure_delay (line 1291)

delay execution of this script for a few seconds and blacklist the remote_addr during the delay

This immediately blacklists the remote address for LOGIN_FAILURE_DELAY_SECONDS seconds. Once that is done, the execution is delayed for that same period of time. After the delay, the temporary blacklisting is removed from the table. The whole purpose of this rapid succession of an INSERT and a DELETE is to prevent brute force attack scripts that do not wait for an answer and/or use multiple connections. This routine defeats that trick, because nothing can be done when an IP-address is blacklisted.

bool|int login_failure_delay (string $remote_addr)
  • string $remote_addr: the remote IP-address that is the origin of the failure
login_failure_increment (line 1313)

add 1 point to score for a particular IP-address and failed procedure, return the new score

This records a login failure in a table and returns the the number of failures for the specified procedure in the past T1 minutes.

  • return: the current score
int login_failure_increment (string $remote_addr, int $procedure, [string $username = ''])
  • string $remote_addr: the remote IP-address that is the origin of the failure
  • int $procedure: indicates in which procedure the user failed
  • string $username: extra information, could be useful for troubleshooting afterwards
login_failure_reset (line 1244)

deactivate all login failures/blacklisting scores for remote_addr

This resets all the scores for all failed login attempts and blacklistings for the specified IP-addres. The records in the login_failures table are deactivated by deleting the records for this remote_addr.

Note that the failed logins and the blacklistings are recorded in the log_messages table via logger(). Therefore we can automatically keep this table 'login_failures' clean without cron jobs.

This routine resets _all_ scores, including any blacklisting that might still be active, i.e. which has a datim in the future.

bool login_failure_reset (string $remote_addr)
  • string $remote_addr: the remote IP-address is the origin of the failure
login_is_blacklisted (line 1212)

find out if a remote address is blacklisted at this time

This routine checks if this remote address is blacklisted in the login_failures table with a datim that lies in the future. If this is the case, the address is indeed blacklisted and TRUE is returned. Note that we sum the points much the same way as in login_failure_increment rather than counting 'blacklist-records'.

  • return: FALSE if the IP-address is not blacklisted, TRUE otherwise
  • todo: Should we first change $remote_addr to canonical form for good comparison? (20140912/PF)
  • usedby: mypage_authorisation()
bool login_is_blacklisted (string $remote_addr)
  • string $remote_addr: the remote IP-address to be checked
login_propagate_navigation (line 1502)

construct an action attribute propagating existing parameters

this routine constructs an action value of a form keeping any existing information from $_SERVER['PATH_INFO'] and/or $_GET[], perhaps with additional parameters from the $add-array.

The object of this excercise is to allow the distribution of links like http://exemplum.eu/index.php/area/2/Intranet.html that actually work by first letting the user login (via show_login() etc) and subsequently falling through to the correct page in a single pass. This requires that we keep all parameters the user presented initially, including the PATH_INFO and thE $_GET-parameters. However, this routine also adds the parameters in $add to the mix, allowing the user to return to the login-routine when she is posting her credentials. In other words: we attempt to propagate the place the user wants to navigate to after logging in to the next screen.

Note that it would be weird to propagate the parameter 'logout' while attempting to login; it yields an endless loop and it becomes impossible to login from the screen that is presented. Therefore we unconditionally get rid of the 'logout' parameter while copying $_GET[]. The same logic applies to the login parameter: if we need it to return to loginlib, it should be set (again) via $add; we do not propagate that field from $_GET[]. Finally, those parameters can also occur in $path_info, so we cleanup that string too.

If $propagate is FALSE we don't propagate after all. However, in this case we do combine $path and $add to a single usable href.

  • return: ready to use href
  • todo: Maybe we could insert the parameters from $add into $path_info. OTOH: adding the existing way always works. If it aint broken... (2014-10-09/PF)
string login_propagate_navigation (string $path, [array $add = array()], [bool $propagate = TRUE])
  • string $path: to the PHP-script
  • array $add: has additional parameters to add to the $action
  • bool $propagate: if FALSE don't propagate after all
login_send_bypass (line 858)

send a new (temporary) password to the user via email

This generates a new temporary password for the user, stores it in the user record and sends an email message to the user with the temporary password (in plain text) and further instructions.

Note that the password is valid only for a limited time; sending a password in plain text appears to be an acceptable risk. Note that the limited time is increased with 10% in order to give the user a reasonable margin to enter the correct password.

Also note that the existing salt is used to salt the temporary password; this makes it easier to check for validity of both the regular password and the temporary password lateron.

A log message recording the event is added via logger().

  • return: FALSE on failure, TRUE otherwise
  • uses: logger()
  • uses: $CFG
bool login_send_bypass (array $user)
  • array $user: an associative array with the user record
login_send_confirmation (line 913)

send email to user confirming password change

This sends an email to the user's email addres confirming that the user's password was changed. Note that the new password is _NOT_ sent to the user.

  • return: FALSE on failure, TRUE otherwise
  • uses: $CFG
bool login_send_confirmation (array $user)
  • array $user: an associative array with the user record
login_send_laissez_passer (line 791)

send a special one-time login code to the user via email

This generates a temporary code with which the user can request a new temporary password. This code can be used only once. Note that this code is valid for only a limited time. This code simply overwrites the bypass password (the temporary password) in the user record. This means that if a phase 2 is pending, a new phase 1 will replace the old phase 2.

The temporary code consists of digits and uppercase characters. However, it is longer (20 characters) than the minimum password length of 6, so a brute force on such a code will likely not succeed (36^20 is much more than the usual 62^6).

This routine also brings the user's record into 'bypass mode'. This mode is reset to 'normal' after the user has successfully changed her password.

A log message recording the event is added via logger().

  • return: FALSE on failure otherwise TRUE
  • uses: logger()
  • uses: $CFG
bool login_send_laissez_passer (array $user)
  • array $user: the user record from database
password_hash_check (line 1179)

check equivalency of salt+password against hash

This verifies whether the hash of $salt and $password is the same as $hash. Note that the two hashes are compared in a caseINsensitive way. Usually these hashes are using lowercase hexadecimal digits but a caseINsensitive compare makes A,...,F equivalent to a,...,f.

If the length of the presented $hash is 40 characters, it is assumed that the hash algorithm to use is sha1, otherwise the default algorithm (md5) is used.

  • return: TRUE if salt+password are equivalent to hash, FALSE otherwise
  • todo: Now if the sha1-hash was compressed into 5 or 6 bits/char instead of hexadecimal digits this routine would fail miserably, so don't do that.
  • uses: was_password_hash()
bool password_hash_check (string $salt, string $password, string $hash)
  • string $salt: salt
  • string $password: password to check
  • string $hash: hash to check against
password_salt (line 1193)

generate a quasi random string to salt the password hash

this generates a quasi-randomg string of digits and letters to be used as a salt when calculating a password hash.

  • return: quasi-random string
string password_salt ([int $length = 12])
  • int $length: the number of characters in the generated string
show_login (line 625)

show complete login dialog and exit

There are different variations of this dialog.

  1. LOGIN_PROCEDURE_NORMAL Plain login
       (message)
       Username: _____
       Password: _____
       [OK]
        
This screen is used for plain user authentication. As a rule the user uses the correct primary password to authenticate. However, it is also possible to enter the 'bypass' password instead. If the authentication fails, that fact is recorded. If the number of failures exceeds threshold N, the user is shown screen #3 LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER. If the number is still below N screen #1 is shown again.

The link <forgotten password?> takes the user directly to screen #3 LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER.

2. LOGIN_PROCEDURE_CHANGE_PASSWORD - Login/change password

   (message)
   Username: _____
   Old password: _____
   New password1: _____
   New password2: _____
   [OK]
This screen is used to change the user's password. If both new passwords are different, the user is redirected to the same screen #3 until she gets it right. Otherwise, if the old password is either the valid original password OR the bypass password, the password is changed and the mode is reset to 'normal'. The one-time codes and the bypass password are reset. Also, as a result, the user is logged in. If the user failed to enter the proper old password more than N times, the mode is also reset to normal (invalidating the laissez-passer and the bypass password) and the user is dropped at a screen basically telling her to contact the webmaster. In this process the user is also logged out if necessary.

3. LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER Request bypass

   (message)
   Username: _____
   Email: _____
   [OK]
This screen is used to help the user reset her password. It is displayed automatically after N failed login attempts. This screen can also be reached via the <forgot password?> link in screen #1.

If the user presents an invalid combination of username and email address, this failure is also recorded. If the number of failures has reached the threshold N, the user is taken to a screen that basically tells the user ask the webmaster for assistance and that's that.

If the user presents a valid combination of username and email address, an email with a message like 'click the link below for a new password' is sent to the email address. After that mail is sent a screen is displayed, basically telling the user to await further instructions that were sent via mail.

Note that resetting the password is a two-step process. First the user is sent a one-time code laissez-passer embedded in a link. Clicking the link before it expires (after T2 minutes) yields a second emai message containing a bypass password that can be used to login and subsequently change the primary password. After that both the laissez-passer and the bypass password are invalidated.

4. LOGIN_PROCEDURE_SEND_BYPASS - Send a temporary password

   (message)
   Username: _____
   One-time code: _____
   [OK]
Phase 2 of the forgot password procedure.

5. LOGIN_PROCEDURE_MESSAGE_BOX Alert

   (message)
   [OK]

This screen is user to communicate various messages to the user, e.g. 'check your mail for instructions', 'contact webmaster', etc.

Note: the $message receives special treatment. The actual message is prefixed with the word 'Message: ' and the combination is wrapped within a B-tag and a SPAN. By carefully changing the style of those tags, we end up either with the bare $message with a yellow background if style is ON in the user's browser, OR 'Message: $message in bold face if the style is OFF. This gives good results in a text browser, eg. lynx.

  • return: this routine never returns but it does send a page to the user
void show_login (int $dialog, [string $message = ''], [bool $propagate = TRUE])
  • int $dialog: is the screen variant to show, could be 1,...,5
  • string $message: the message to show just above the first field, used for feedback to user
  • bool $propagate: TRUE means propagate the existing parameters, FALSE means don't propagate
was_login (line 282)

execute the selected login procedure

The login process is controlled via the parameter 'login' provided by the user via 'index.php?login=N or via the 'action' property in a HTML-form. These numbers correspond to the LOGIN_PROCEDURE_* constants defined near the top of this file. Here's a reminder:

  1. LOGIN_PROCEDURE_NORMAL this is the usual procedure for logging in
  2. LOGIN_PROCEDURE_CHANGE_PASSWORD this is the procedure to change the user's password
  3. LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER this is phase 1 of the 'forgot password' procedure
  4. LOGIN_PROCEDURE_SEND_BYPASS this is phase 2 of the 'forgot password' procedure
It is also possible that code in main_index.php or main_admin.php calls this routine without the login=N parameter, e.g. when a user attempts to access a page in an intranet without being logged in already.

Note that this routine only returns to the caller after either a succesful regular login (i.e. after completing LOGIN_PROCEDURE_NORMAL). All the other variants and error conditions yield another screen and an immediate exit and hence no return to caller. If this routine returns, it returns the user_id of the authenticated user (the primary key into the users table). It is up to the caller to retrieve additional information about this user; any information read from the database during login is discarded. This prevents password hashes still lying around.

Note that a successful login has the side effect of garbage collection: whenever we experience a successful login any obsolete sessions are removed. This makes sure that locked records eventually will be unlocked, once the corresponding session no longer exists. The garbage collection routine is also called from the PHP session handler every once in a while, but here we make 100% sure that garbage is collected at least at every login. (Note: obsolete sessions should not be a problem for visitors that are not logged in, because you have to be logged in to be able to lock a record.)

Note that in LOGIN_PROCEDURE_SEND_BYPASS we refrain from propagating the parameters. because the user might arrive here with GET['code'] and GET['username']. We don't want to propagate that. Side effect is that nothing is propagated, but what's the point anyway when you are busy resetting your password. Not having parameters propagate is not important at that time.

void|int was_login ([int $procedure = LOGIN_PROCEDURE_SHOWLOGIN], [string $message = ''])
  • int $procedure: the login procedure to execute
  • string $message: the message to display when showing the login dialog
was_logout (line 189)

end a session (logout the user) and maybe redirect

This routine ends the current session if it exists (as indicated by the cookie presented by the user's browser). An empty value is sent to the browser (effectively deleting the cookie) and also the session is ended. The routine ends either with showing a generic login dialog OR a redirection to a user-defined page.

Note that as a rule this routine does NOT return but instead calls exit(). However, there are cases where this routine DOES return, notably when no session appears to be established (no cookie submitted by the browser. If the routine does return, the status is equivalent to a logged out user; no session exists so the user simply should not be logged in.

On successful logout, the user usually is redirected to her own redirect-page. Thos depends on the $redirect_flag: if it is FALSE we always force a normal login dialog even if $redirect is specified. This is used from was_login() to make sure that we end in a login dialog after (forcefully) logging out the user. This also gets rid of the 'logout=' parameter preventing a logout loop.

void was_logout ([bool $redirect_flag = TRUE], [int $procedure = LOGIN_PROCEDURE_NORMAL])
  • bool $redirect_flag: TRUE redirects to $_SESSION['redirect'], FALSE yields login dialog
  • int $procedure: determines which login dialog to show
was_password_hash (line 1149)

calculate a hash from a salt and a password

This routine constructs a hash of the combination of salt and password. By default the md5() function is used to calculate a 32-character long string of hexadcimal digits. If the parameter $algorithm is 1 then the sha1() function is used and a 40-character long string of hexadecimal digits is returned.

Note that we do not use the crypt() function because that could introduce a portability issue. If a website is migrated to another machine, the used crypt algoritm might no longer be available, and that would effectively lock out all users. Both md5() and sha1() are standard PHP-functions (since 4.3.x) and should be portable, which makes any installed table of users portable too.

Note that this routine used to be called 'password_hash'. PHP 5.5.0 introduced a function called 'password_hash' which clashed with our own version, hence we renamed this function to was_password_hash().

  • return: a hexadecimal representation of the hash of the combination of salt and password
  • usedby: password_hash_check()
string was_password_hash (string $salt, string $password, [int $algorithm = 0])
  • string $salt
  • string $password
  • int $algorithm: (optional) algorithm to use: 0=md5, 1=sha1

Documentation generated on Tue, 28 Jun 2016 19:10:07 +0200 by phpDocumentor 1.4.0