PHP password_hash() vs. Postgres crypt() - php

I am using a Postgres 9.3 database as a back-end for a web application. I use PHP 5.5.7 to connect to the database and return JSON for the front-end AJAX calls.
I'm trying to decide on where to put the user authentication logic.
I am not a security expert; however, I am familiar with PHP's new password_*() functions and I have a strong grasp of what is going on under the hood. I am also familiar with the Postgres Extension pgcrypto and the associated crypt() function.
My question is, does it make sense to use PHP or Postgres to hash passwords?
I was curious as to how these functions differ, so I made a password hash in PHP and then gave it to Postgres to see if Postgres uses the same algorithm. Given the same parameters, Postgres returned a different result when compared to PHP (not unexpected, but with noting).
PHP
password_hash('password', PASSWORD_BCRYPT, ["cost" => 15]);
output: $2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu
Postgres
SELECT '$2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu' = crypt('password', '$2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu')
output: false
PHP vs. Postgres
Given that these processes are different, I wonder if one is better then the other? Is one more, or less, secure?
Some other thoughts:
I currently have all logic stored in the database (in views, functions, constraints, etc.) so if I ever need to use a different front-end I don't have to worry about missing logic. Calculating password hashes in PHP would effectively require all requests to pass through PHP to access the database.
On the other hand, putting the logic in the database would allow me the flexibility to use other connection options; however, all of the Postgres queries are logged. I can't disable the logs because of the WAL used in replication. This seems like a big security hole.
Am I on the right track here? What am I missing?
EDIT
I just looked at another message thread and found some more information.
Putting the logic in Postgres would require the database to processes and perform the hash operation. This would be a bad thing for other users and batch jobs that need those resources.
Not only would the hash slow down normal operations, it would make the whole system more vulnerable to DOS attacks.
Our simple web servers with load balancing would address both issues...
Again, am I on the right track here? What else am I missing?

For the difference between versions 2y and 2a, see this thread and the various links within it:
https://security.stackexchange.com/questions/20541/insecure-versions-of-crypt-hashes
My understanding is there was a problem with the 2a implementation in PHP until v.5.3.8, though only for strings that contained non-ascii chars. PgCrypto, as you noted, doesn't "speak" 2y for some reason, and I'd assume it suffers so such problem. (Perhaps report this as a bug?)
Apart from the points raised in the latter, you nailed the main security difference between the two in your question: systematically hashing the password within the database is convenient but implies that you send it to your database in clear text, where it can (and will) be logged — or snooped at outright, if your DB connection is not encrypted.
In an ideal world, you'd hash the password in the client app using javascript before it's even sent to PHP. The next best thing is to send it using SSL to PHP, then hash it using PHP before sending it to the DB.
Aside: I'm pretty certain that PHP's crypt can generate a (secure) 2a version hash if you need interoperability for some reason.

Related

Encryption of data introduced into Mysql database then read by PHP

I am building my own game panel and it required the user to introduce into the database the user and password of their linux server. This will allow the game panel manage their servers. My problem now is this:
When the user introduces his linux user and password it is stored in plain text into database and then it is retrieved in the PHP script. However, if the database ever gets breached the hackers will be able to breach their servers as well and I want to avoid that at all costs.
At the moment I am using register and login system in which I implemented password_hash($password, PASSWORD_BCRYPT) and password_verify. I tried to use the method to my problem but it required user input in order to match the stored password with it.
All I need is to store an user and password into database in the most secure what that when a hacker manages to breach my database all the data there will be useless to him.
I am a newbie PHP web developer working with Javascript and BASH. I am still a newbie in these to fields as well. So if you can offer my newbie-friendly answers I would more than thankful to you. (as my first question was answered within hours I am positive I will find a solution to this one as well)
I'm getting informed on data encryption in these days as well, especially to implement the "Privacy by design" concept legally required by the GDPR (The EU General Data Protection Regulation).
Using PHP and MySQL there are two main ways you can encrypt your data, getting it ready to be stored into your DB:
Using MySQL functions AES_ENCRYPT / AES_DECRYPT
Using OpenSSL functions in PHP, in particular openssl_encrypt and openssl_decrypt (it provides, among others, an AES-256-CBC encryption). To know how to use it, you can have a look directly at the examples in the functions' documentation or check out this answer on StackExchange.
What I suggest you, if you have the opportunity, is to use Laravel and its encrypter, which provides all you need to easy encrypt your data using OpenSSL with AES-256-CBC.

Security for storing Data with PHP/PDO

After researching some hours about the topic of securing stored data I am a little bit confused of what is the best way to go now.
I have a databank for my (SSL) website where I am the only one that has access to it (hackers not counted). The login data is stored in a configuration file outside of the document root. In the database I have stuff like names and adresses from my clients and I am now worried that I need to implement all the security measures put forward by cryptography experts like in this answer (How do you Encrypt and Decrypt a PHP String?) or as asked here (Storing sensitive data securely in a database).
Since neither in my PDO/SQL and PHP seminars nor in regular posts here on stackoverflow I see these encryption and authentication methods being used or more specifically e.g. the keys when explaining PDO and PHP commands like INSERT INTO ... etc. I am unsure if it is now necessary to deploy encryption and authentication measures on every entry in my databank (is it even possible to do this afterwards?). The safety measures I have been informed about in the tutorials and articles are to use PDO's prepared statements.
If encryption and authentication is what I have to do, which is probably the case: Would it not be the most convenient and fastest way to simply use password_verify() and password_hash() for every sensitive data entry like it is done for passwords?
EDIT password_verify() and password_hash() are hashing (not encryption) methods, meaning that the data is irretrievably mangled and can only be confirmed but not read.
There are different types of database encryption, and depending on what data you want to protect, and why, you will do different things.
1) Database level encryption / Transparent data encryption
This is where your RDBMS encrypts everything for you at a file level. This means if anyone has access to the hard drive, or back-up media, they should not be able to access the data. See here for how to do it with MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-tablespace-encryption.html (note this is not a PCI compiant solution, you'll need MySQL Enterprise Edition or another Enterprise database, or further security measures for that).
Note this does not protect your data if your application is compromised.
2) Field level encryption
You can encrypt data to be stored in any field you like. Here's a good answer that deals with that: https://stackoverflow.com/a/10945097/
The drawback of field level encryption is that you can't then query across the data. In each case you'll need to pull the data into your application, and then decrypt it one field at a time.
Note this does not protect your data if your application is compromised.
Note also the difference between 'encryption' and 'hashing' (password_verify and password_hash are about hashing)...encryption lets you secure data, store it and retrieve it. Hashing by definition does not let you retrieve the data.
In all cases the most important thing is to secure your application. Encryption of the underlying data is very much a secondary concern.
Since your web server (presumably) will have to have access to the data, it's somewhat useless to encrypt it at rest when the web server can (will have to be able to) decrypt it. Why? Because the web server is often the weak link. If an attacker can get access to it, they can do anything it can do, including decrypting the data.
Encrypting data at rest is only useful to prevent backchannel leaks, like improperly handled backups (which you're doing, right, right?) which dump the data in plaintext to a file which then inadvertently gets lost somewhere. To prevent that you should use whatever at-rest encryption your database offers transparent to the client; i.e. it's not something you should burden the application logic with if it's not integral to your application, it's something the database should worry about.
password_hash is a hash, it doesn't encrypt data, it irretrievably mangles it so it's impossible to get the original back from it. It's great for storing credentials which you need to confirm but not read; it's useless for anything else.
The main security points are to isolate your database server "physically", i.e. to not grant any access to it from anything but the web server; be very restrictive and specific about that. That then means the weak spots are at those ingress points like your web server. Ensure your web server is locked down as much as possible, exposes as little attack surface as possible (no unnecessary open ports or running services) and that your application code running on it doesn't allow any exploits (yes, that's the hard part that takes knowledge and discipline).
You can further tighten it down by segregating access to the database with different accounts which have different permission levels; i.e. some accounts only have read access to certain tables while others have read/write access to other tables. If you can split up your web server(s) into separate roles which all only need specific limited access, this further enhances security by avoiding vulnerabilities in one part enabling exploits in another.

Creating PHP Admin Script for only one user

I have a website which is a front end to a MySQL database. This data is also exposed via a web service (fur use in Android application).
Currently I am maintaining the data via PHPMyAdmin but this is cumbersome and not that "pretty".
I want to create an /admin module where I log in (against values in a PHP Varialbe or a MySQL table) and once logged in I can edit,delete,add data.
Questions:
Is it acceptable in terms of security to compare entered credentials against static variables? There will only be one user so I feel like it is overhead to create a table for members.
Any guidelines on going down this route?
I don't see any reason why you couldn't do it this way, assuming you will always have just the one user. The main consideration would be if someone somehow got a look at your code, they would see the stored password. So, you could store it using password_hash to generate a one way hash, and then verify it with password_verify. Here's how I might do it:
Using password_hash(), generate a hash:
// copy the hash output, then delete this code
echo password_hash("thepassword", PASSWORD_DEFAULT);
Then, in your code, store the hash:
// paste hash here
$passwordKey = '$2y$10$j33UPA7gNxSOBsXQcyquLOZRuO6X8k8hZOb1RA79iN8gLlqp9eIPO';
Then run password_verify() to check the user input:
if (password_verify($userInput, $passwordKey))
echo "correct";
else echo "incorrect";
Demo: http://3v4l.org/PknTI
consider looking at this manual for encryption methods with php. My gut instinct is to make a user table, or at least a table with just the encrypted password in it, rather than just checking the variable against a value.
That being said, if you don't think anyone will really even consider trying to fool around with the system and get past it, you probably don't need to be this cautious. I've built a few front-ends as well as back-ends to communicate somewhat friendly with a database, and I've never experienced a considerable amount pressure on the security.
Hope this helps, if you have any questions about how I've designed the ones I've made, feel free to email me at spencer#codeshrub.com
If phpmyadmin is installed at your server localy, than it is NOT securely at all
You can use any MySQL client that supports ssh connection. E.g. Sequel Pro for Mac or HeidiSQL for WIN.
Also, you can use basic HTTP Authentication for you admin script. But, since it's very simple it's not protect you from bruteforce or password leaking, etc.
Anyway, if you prefer security you need to make your own authentication in PHP, You can use this package for example. It is simple and has many security features

Where and how to store MySQL passwords available to PHP

I am using PHP with a singleton PDO to access the database, and it it obviously need MySQL's username and password.
As we all should know, the username and password should not be stored in a public directory.
I can therefore do something like require 'some_path/my_secrets.php'; which sets a bunch of variables, but then these variables are defined potentially globally which is not a good idea (granted, not globally when using a singleton, but still). Okay, I can only require the secret file within some function, but that is a lot to remember...
Is there a better way to make private data available to the PHP script? Also, any other steps I should be taking? Thank you
Most systems I know have a .htaccess protected include file. Inside you define a config array and done. Maybe not the most secure way of doing it but that is many shops, CRMs and other web services do it.
I had the same problem and initially
DB passwords were stored in an include file within the includes directory (ie to prevent a incidental PHP code display directly from the web files)
then came another idea, a bit more complex but still pretty doable
Make a C program that owns the DB data encoded and delivers the data from a system call. The source code (that includes the encoded passwords) is owned somewhere safe. The C code has to perform some checks to ensure the call is made from PHP etc...
but this is pretty expensive - C is fast, but loading all the time the passwords through system is expensive. Therefore adding APC to the game makes the whole thing easier and faster
during the first request, load the DB data into APC permanent variables - thus the data is in memory and more difficult to obtain from outside. Typically the algorithm is
algo
Check if APC variables are set
If yes use them
If no load them from C program, only once
APC documentation
Another idea, using php-fpm for instance is to set an environment variable within the fpm configuration (readable only by root) that contains the passwords
Finally, you could also create your own PHP extension that provides the data from the C code (extensions are usually written in C). This is some extension documentation.
This is not the definitive answer in how to prevent passwords stealing, but at least it would make more difficult for the hacker to determine the passwords - and would require also more knowledge.
Your solution is fine.
Most of the suggested solutions are just exaggerated as although they may higher the level of security a bit they are not worth the additional effort.
Because the security should not only rely on the secrecy of the password. At best, even if the password get’s revealed, its knowledge is worthless for an attacker as he cannot use it.
This means, use a MySQL user dedicated to your application with permissions following the principle of least privilege and only allow the access to the database from that application’s web server (see MySQL Access Privilege System).
First off, I would say, unless your PHP app needs it, restrict the permissions of the app's database account as much as possible (e.g.: read access on appropriate tables, perhaps write access as few as possible). If your app needs admin access to create tables, etc., that's a whole 'nother can of worms.
Secondly, as ring0 suggests, don't store the database password in plain text. I would recommend using a hashing API to store a hash of your password, such as this: https://gist.github.com/nikic/3707231. And of course, the hash might be best stored in some other 3rd place (at least a separate file). If your users are trustworthy, and you can figure out a way, you could have the hash be computed from the user's log-in information, but that might require separate entries in your password file for each user (because each hashed DB password will be different).
There is never a foolproof way, and I'm not a security expert, but I know plain text is always bad for storing passwords, so I think this is a step in the right direction.

Encryption and hashing in MySQL versus PHP

I am writing some simple login scripts. I am just wondering, is there any advantage of using the hashing and encryption functions in MySQL over PHP or the other way around?
I know using a stored procedure, I could possibly be transmitting sensitive information insecure. On the other hand, it may be simpler to maintain.
Are there any benefits of using either?
The only issue I see of using mysql for encrypting sensible data is that if your web server that is running php is in a different location of your mysql, you may send sensible unencrypted data over the network that is communicating this two parties.
I would definitely use PHP over MySQL to hash passwords. There are so many ways that a query could be stored and viewed, it could be bad if there are queries like this that end up getting stored somewhere:
SELECT id FROM users WHERE username = 'User123' AND password = MD5(CONCAT('SecretSalt','MyPassword'))
If you're storing passwords, use a hashing function designed to be difficult to crack. bcrypt is a reasonable choice and many answers here go into detail on how to implement it.
MySQL's hashing methods are not as secure as this and are intended for other purposes, such as hashing documents to check for duplication.

Categories