Given the sensitivity of the data inherent in PHPCredLocker's intended purpose, security has been given priority over any other consideration. If something is convenient, but lowers security it's not generally been implemented.
A number of potential attack vectors have been identified and measures put in place to mitigate the risk of such an attack, these are
- Authentication Attempts (Brute-forcing of logins etc.)
- Database retrieval (SQL injection etc)
- User Session Hijacking
- Direct Script Access
- Cross-Site Scripting (XSS)
- User Error
This documentation details the measures put in place to mitigate each of these risks.
The authentication process will probably always be the weakest link in the chain. By it's very nature you need to allow valid users through, an inconvenient loophole which an attacker will attempt to exploit by pretending to be an authorised user. To make this harder, PHPCredLocker implements the following
- Brute Force detection (resulting in a temporary banning of the IP address)
- Minimum password strength requirements
The threshold for each of the above is specified by the systems super-administrator, but defaults to strong protection.
Suspension of a targeted account is planned in a future release to combat the issue of a brute-force attempt originating from multiple IP's (such as a botnet or cloud computing resource).
It should go without saying that all input is sanitised before going anywhere near the database. However, it's not impossible that an attacker may be able to retrieve PHPCredLocker's database by other means (whether through a plugin that doesn't sanitise, or due to a badly configured webserver).
To reduce the potential fallout of this, almost all database content is heavily encrypted using a number of keys
- Credential Types (CredTypes)
- CredType Specific keys
Data that is not necessarily sensitive, but may be of use to an attacker is encrypted to reduce the utility of any database output (whilst encrypting group names may seem un-necessary, if you have a group called Server Admins an attacker will be able to see which encrypted records may be worth trying to crack - the same goes for Credential Types, the title root passwords is like a red rag to a bull!).
Each stored credential is encrypted using a key unique to that Credential Type. So all Joomla passwords are encrypted with the same key, whilst all FTP Passwords are encrypted with another.
The system contains no default keys, all are generated during install.
Supported Encryption Engines
PHPCredLocker currently supports two encryption engines - MCrypt and OpenSSL. The latter is available by default in PHP > 5.3.3 and is the recommended engine.
Table Name Obfuscation
Although technically security by obscurity, a unique prefix (generated at install) is added to table names to help reduce the ability of an (inexperienced) attacker to perform SQL injection. In reality, this measure alone is unlikely to stop any but the most incompetent of attackers, but it still seemed worth implementing!
Example Database Dump
If an attacker were able to download a copy of the database, (s)he'd see something similar to the following
Very little use without the relevant encryption keys. The number of encryption keys in use within the system is number of credentials types + 4. As the attacker has no indication of which stored credentials (or credtypes) relate to which level of access, it's unlikely to be worth trying to crack the encryption. User passwords (tbl_Users) are stored as encrypted salted hashes, so the user's password remains almost completely irrecoverable.
User Session Hijacking
If an attacker is unable to log in as a user (because of strong passwords and brute-force protection) and can't utilise database dumps, another option might be to wait for an authorised user to log in and then attempt to steal their session. As the session ID is provided by PHP/Apache and recorded in a cookie, it's more than possible for this to occur.
Rather than having to document how to configure Apache/PHP to reduce this risk, a second factor has been added. An additional session cookie is set, using measures to ensure that the cookie is only provided to the directory containing PHPCredLocker, and - where the admin has set Force SSL to on - to only ever provide the cookie over an SSL connection.
The content of this cookie is used to identify a session file (only available to the server), who's content is then checked against the session record in the database.
This area could do with further enhancement, but is still pretty well secured.
Direct Script Access
Attackers may try to find out local paths by directly accessing scripts in order to try and force output of an error. To prevent this, two measure have been implemented. Firstly, PHPCredLocker forces error reporting to NONE when accessed correctly (to prevent accidental release of this information if an error does occur).
Secondly, all scripts require that a specific constant be defined, otherwise they exit immediately, before anything which may result in an error occurs.
Cross Site Scripting (XSS)
PHPCredLocker never uses the content of either POST data or the request URI to populate content, this helps prevent XSS attacks as it prevents malicious tags from being embedded into the request.
Whilst an attacker may be unable to crack data obtained through SQLi, the risk that they may be able to insert data has been considered. All data is passed through the crypto libraries and through htmlspecialchars, so it should be impossible to insert malicious HTML elements without knowing the systems encryption keys (which would render the attack pointless as the stored data could just be decrypted).
In any system, the biggest risk is usually the user. User's leave windows open, email things they shouldn't and write passwords down in places they shouldn't.
There's very little PHPCredLocker can do about many of the mistakes users make in the real world, but it can take steps to prevent some of them. For example:
- A users session expires after a set period, regardless of their activity on the system - so an unattended laptop is only a risk for a short-time even if an unauthorised user is browsing the pages
- Passwords are only displayed for a matter of seconds. Users have to click to display the password, and after a specified period (default 30 seconds) the password is hidden (the password is not included within the page markup, a valid session is required to view any password)
Users can also be a little nosy at times, so to prevent users from seeing credentials that they do not need, system admins can define user groups. Both customers and the credentials themselves can be assigned to groups, so you can limit FTP passwords to server admins and Joomla passwords to Web developers (for example).