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.
Related
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.
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
I would like to create a PHP extension to do some specific crystallographic functionality.
Is it possible for an attacker to disassemble (or somehow xdebug) the extension to find out how it works?
Could the attacker find out constants or variables which are set inside of the extension (for inst. a password, salt, etc...)?
UPDATE
The idea was:
I want to store some data in DB encrypted, I also want to make sure that every user has his own password/salt, so nobody could access data of somebody else in case the attacker would find a hole in the access control.
I could to the encryption in PHP. But if somebody gains the access to the web directory, he can easily see how I do that... he can just take the data and decrypt it at home.
I could make the extension. The attacker would need gain access to the whole filesystem to get the extension. I could limit the extension use just for the server's IP address (so the attacker would not be able to take the data out from the server that easily). Wouldn't it be more secure? Is there some other way how to do it better?
Is it possible for an attacker to disassemble the extension to find out how it works
Yes. This is pretty trivial to get code back out. The variable names will be stripped (assuming it's a non-debug build), but it's 100% possible to get the code.
Could the attacker find out constants or variables which are set inside of the extension (for inst. a password, salt, etc...)?
Yes, these are always stored in the file in plain text. In fact, there's a unix command strings which will extract it for you.
A better solution would be to look at the problem you're trying to solve, figure out what attack vectors you want to protect against, and then mitigating them. There is no magic solution to any of it.
I have a cache library that stores cached data in normal php files, with the data stored in arrays.
An example of a cache file:
cache_userID.php:
$userCache['userID']=2354654654;
$userCache['userName']=foo;
$userCache['userPass']=salted-and-hashed-pass;
It works like a charm. So I'm thinking of using it to store user data (like the above example) to save DB querying. I've already tested it, and it does result in a noticeably faster page load time then fetching from the DB (which is why I want to do it).
I'm not sure if this is really safe though. The password and other sensitive information is salted and hashed. Would it be possible for anyone to be able to steal this data? With the exception of if they had the FTP details to access the source code (which won't be the case).
No! Every extra place you store a password (or password hash which is still sensitive) is another place that they can leak from. This is one of the reasons why SSL pages are not cached: because sensitive information should not be cached.
Good authentication code (like the sort you find in SSH) even goes to the effort of marking the memory region in which the password is stored as unswappable so it can't be written to disk by the operating system.
The risk of sensitive data leaking from this cache may be low but by doing this you have increased the risk. By placing this data in a local PHP file, it can now be accessed by any local file inclusion vulnerability. It may take more than just the local file inclusion to actually echo the passwords out to the screen. Before this cache existed, an SQL injection vulnerability or a complete server compromise was probably required to even access the password hashes, now those and local file inclusion can access the hashes.
It is fine to store other, less sensitive data in multiple places to improve page load speeds but passwords and password hashes should be off limits.
You can avoid having to calculate and look up the password hash on every page load for authenticated users by storing an authentication token. This should be randomly generated (so it's difficult to predict) at login time and should be short-lived. This is exactly what a PHP session ID is and it is perfectly adequate to verify that your users are properly authenticated after the first check where you compare passwords.
It just occurred to me that if you are querying the database and calculating the password hash on every page load, you must have stored the password (or potentially password hash) with the client somewhere, probably in the cookie and this sensitive data is being sent over the internet for every page request. This is bad practice in general and will result in the password (or password hash) being saved on the user's hard drive and potentially intermediate proxies unless you are using SSL for every page.
P.S.
I'm curious why including a local file is noticeably faster than what should be a simple key-value lookup from your database. My guess is you either have horrendous latency on your network or contention on your users table. Either one really needs fixing.
Security-wise: as long as your cache files aren't in a www-accessible location then it should be secure enough (assuming your code has no flaws!). Don't rely on PHP tags hiding your content... the engine can fail and expose this data (although it is rare, it DOES happen).
Performance-wise: Do you really need ALL the data of a user, every time you want to know ANYTHING at all? I wonder why your database would be so slow. Have you set up proper indexes etc.? Probably worth looking into that instead.
As long as the file contains <?php the data will be safe as users cannot see PHP sourcecode unless they have FTP access or there is a security hole allowing them to read arbitrary files.
However, you should protect your cache folder either by moving it outside the document root or blocking any http access to it via the webserver config (e.g. a deny from all in your .htaccess) anyway.
I'm going to be implementing a PHP/mySQL setup to store credit card information.
It seems like AES_ENCRYPT/AES_DECRYPT is the way to go,
but I'm still confused on one point:
How do I keep the encryption key secure?
Hardwiring it into my PHP scripts (which will live on the same server as the db) seems like a major security hole.
What's the "best practice" solution here?
You should think long and hard about whether you REALLY need to keep the CC#. If you don't have a great reason, DON'T! Every other week you hear about some company being compromised and CC#'s being stolen. All these companies made a fatal flaw - they kept too much information. Keep the CC# until the transaction clears. After that, delete it.
As far as securing the server, the best course of action is to secure the hardware and use the internal system socket to MySQL, and make sure to block any network access to the MySQL server. Make sure you're using both your system permissions and the MySQL permissions to allow as little access as needed. For some scripts, you might consider write-only authentication. There's really no encryption method that will be foolproof (as you will always need to decrypt, and thus must store the key). This is not to say you shouldn't - you can store your key in one location and if you detect system compromise you can destroy the file and render the data useless.
MySQL, there is six easy steps you can do to secure your sensitive data.
Step 1: Remove wildcards in the grant tables
Step 2: Require the use of secure passwords
Note: Use the MySQL “--secure-auth” option to prevent the use of older, less secure MySQL password formats.
Step 3: Check the permissions of configuration files
Step 4: Encrypt client-server transmissions
Step 5: Disable remote access
Step 6: Actively monitor the MySQL access log
Security Tools
I agree, but don't the cc if you don't need too. But if you really have too, make sure the file that have it is not accessible on the web. You can write a binary that would return the key. This way it's not store in clear text. But if your server is compromise it's still easy to get it.
the security you need depends on your application. for example, if the only time the cc# will be used is when the user is logged in (thin online store type scenario), then you can encrypt the cc# with the a hash of the user's plain-text password, a per-user salt, and a dedicated cc# salt. do not store this value permanently.
since you're not storing this value, the only time you can get this value is when the user enters their password to log in. just make sure you have good session expiration and garbage collection policies in place.
if this situation does not apply to you, please describe your situation in more detail so we can provide a more appropriate answer.
Put your database files outside computer lets say external hdd and keep it at safe place. Works only if you can develop this project at only place where this external drive is placed :)
Or you can at least protect those files using file system encryption tools like
https://itsfoss.com/password-protect-folder-linux/
In case of production environment I agree with Kyle Cronin.