When a PHP application makes a database connection it of course generally needs to pass a login and password. If I'm using a single, minimum-permission login for my application, then the PHP needs to know that login and password somewhere. What is the best way to secure that password? It seems like just writing it in the PHP code isn't a good idea.
Several people misread this as a question about how to store passwords in a database. That is wrong. It is about how to store the password that lets you get to the database.
The usual solution is to move the password out of source-code into a configuration file. Then leave administration and securing that configuration file up to your system administrators. That way developers do not need to know anything about the production passwords, and there is no record of the password in your source-control.
If you're hosting on someone else's server and don't have access outside your webroot, you can always put your password and/or database connection in a file and then lock the file using a .htaccess:
<files mypasswdfile>
order allow,deny
deny from all
</files>
The most secure way is to not have the information specified in your PHP code at all.
If you're using Apache that means to set the connection details in your httpd.conf or virtual hosts file file. If you do that you can call mysql_connect() with no parameters, which means PHP will never ever output your information.
This is how you specify these values in those files:
php_value mysql.default.user myusername
php_value mysql.default.password mypassword
php_value mysql.default.host server
Then you open your mysql connection like this:
<?php
$db = mysqli_connect();
Or like this:
<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
ini_get("mysql.default.password"),
ini_get("mysql.default.host"));
Store them in a file outside web root.
For extremely secure systems we encrypt the database password in a configuration file (which itself is secured by the system administrator). On application/server startup the application then prompts the system administrator for the decryption key. The database password is then read from the config file, decrypted, and stored in memory for future use. Still not 100% secure since it is stored in memory decrypted, but you have to call it 'secure enough' at some point!
This solution is general, in that it is useful for both open and closed source applications.
Create an OS user for your application. See http://en.wikipedia.org/wiki/Principle_of_least_privilege
Create a (non-session) OS environment variable for that user, with the password
Run the application as that user
Advantages:
You won't check your passwords into source control by accident, because you can't
You won't accidentally screw up file permissions. Well, you might, but it won't affect this.
Can only be read by root or that user. Root can read all your files and encryption keys anyways.
If you use encryption, how are you storing the key securely?
Works x-platform
Be sure to not pass the envvar to untrusted child processes
This method is suggested by Heroku, who are very successful.
if it is possible to create the database connection in the same file where the credentials are stored. Inline the credentials in the connect statement.
mysql_connect("localhost", "me", "mypass");
Otherwise it is best to unset the credentials after the connect statement, because credentials that are not in memory, can't be read from memory ;)
include("/outside-webroot/db_settings.php");
mysql_connect("localhost", $db_user, $db_pass);
unset ($db_user, $db_pass);
If you are using PostgreSQL, then it looks in ~/.pgpass for passwords automatically. See the manual for more information.
Previously we stored DB user/pass in a configuration file, but have since hit paranoid mode -- adopting a policy of Defence in Depth.
If your application is compromised, the user will have read access to your configuration file and so there is potential for a cracker to read this information. Configuration files can also get caught up in version control, or copied around servers.
We have switched to storing user/pass in environment variables set in the Apache VirtualHost. This configuration is only readable by root -- hopefully your Apache user is not running as root.
The con with this is that now the password is in a Global PHP variable.
To mitigate this risk we have the following precautions:
The password is encrypted. We extend the PDO class to include logic for decrypting the password. If someone reads the code where we establish a connection, it won't be obvious that the connection is being established with an encrypted password and not the password itself.
The encrypted password is moved from the global variables into a private variable The application does this immediately to reduce the window that the value is available in the global space.
phpinfo() is disabled. PHPInfo is an easy target to get an overview of everything, including environment variables.
Your choices are kind of limited as as you say you need the password to access the database. One general approach is to store the username and password in a seperate configuration file rather than the main script. Then be sure to store that outside the main web tree. That was if there is a web configuration problem that leaves your php files being simply displayed as text rather than being executed you haven't exposed the password.
Other than that you are on the right lines with minimal access for the account being used. Add to that
Don't use the combination of username/password for anything else
Configure the database server to only accept connections from the web host for that user (localhost is even better if the DB is on the same machine) That way even if the credentials are exposed they are no use to anyone unless they have other access to the machine.
Obfuscate the password (even ROT13 will do) it won't put up much defense if some does get access to the file, but at least it will prevent casual viewing of it.
Peter
We have solved it in this way:
Use memcache on server, with open connection from other password server.
Save to memcache the password (or even all the password.php file encrypted) plus the decrypt key.
The web site, calls the memcache key holding the password file passphrase and decrypt in memory all the passwords.
The password server send a new encrypted password file every 5 minutes.
If you using encrypted password.php on your project, you put an audit, that check if this file was touched externally - or viewed. When this happens, you automatically can clean the memory, as well as close the server for access.
Put the database password in a file, make it read-only to the user serving the files.
Unless you have some means of only allowing the php server process to access the database, this is pretty much all you can do.
If you're talking about the database password, as opposed to the password coming from a browser, the standard practice seems to be to put the database password in a PHP config file on the server.
You just need to be sure that the php file containing the password has appropriate permissions on it. I.e. it should be readable only by the web server and by your user account.
An additional trick is to use a PHP separate configuration file that looks like that :
<?php exit() ?>
[...]
Plain text data including password
This does not prevent you from setting access rules properly. But in the case your web site is hacked, a "require" or an "include" will just exit the script at the first line so it's even harder to get the data.
Nevertheless, do not ever let configuration files in a directory that can be accessed through the web. You should have a "Web" folder containing your controler code, css, pictures and js. That's all. Anything else goes in offline folders.
Just putting it into a config file somewhere is the way it's usually done. Just make sure you:
disallow database access from any servers outside your network,
take care not to accidentally show the password to users (in an error message, or through PHP files accidentally being served as HTML, etcetera.)
Best way is to not store the password at all!
For instance, if you're on a Windows system, and connecting to SQL Server, you can use Integrated Authentication to connect to the database without a password, using the current process's identity.
If you do need to connect with a password, first encrypt it, using strong encryption (e.g. using AES-256, and then protect the encryption key, or using asymmetric encryption and have the OS protect the cert), and then store it in a configuration file (outside of the web directory) with strong ACLs.
Actually, the best practice is to store your database crendentials in environment variables because :
These credentials are dependant to environment, it means that you won't have the same credentials in dev/prod. Storing them in the same file for all environment is a mistake.
Credentials are not related to business logic which means login and password have nothing to do in your code.
You can set environment variables without creating any business code class file, which means you will never make the mistake of adding the credential files to a commit in Git.
Environments variables are superglobales : you can use them everywhere in your code without including any file.
How to use them ?
Using the $_ENV array :
Setting : $_ENV['MYVAR'] = $myvar
Getting : echo $_ENV["MYVAR"]
Using the php functions :
Setting with the putenv function - putenv("MYVAR=$myvar");
Getting with the getenv function - getenv('MYVAR');
In vhosts files and .htaccess but it's not recommended since its in another file and its not resolving the problem by doing it this way.
You can easily drop a file such as envvars.php with all environment variables inside and execute it (php envvars.php) and delete it. It's a bit old school, but it still work and you don't have any file with your credentials in the server, and no credentials in your code. Since it's a bit laborious, frameworks do it better.
Example with Symfony (ok its not only PHP)
The modern frameworks such as Symfony recommends using environment variables, and store them in a .env not commited file or directly in command lines which means you wether can do :
With CLI : symfony var:set FOO=bar --env-level
With .env or .env.local : FOO="bar"
Documentation :
Today, I was able to create totally random and invalid SPN using the setspn command, but I dont understand why invalid SPNs are allowed. For example:
setspn -s RandomSvc/randomname.random.random valid_user was run successfully for valid_user in my domain (I substitute the actual user name here, but the user is a valid user in the domain).
Then if I do setspn -l valid_user, it will list this invalid entry.
I guess nobody can actually connect to this service since it does not exist. however, if I try to add a valid SPN, but typed it by mistake, I won't notice it until my application gives me an error. So why setspn does not do any validation (other than checking for duplicate with -s)?
The setspn command won't stop you from creating an invalid SPN, and for good reason, so there is no actual problem here believe it or not. Your definition of a valid SPN - that of a representation of an actual service running on an actual machine having a host name in DNS which can be reached over TCP/IP, is not going to be enforced by setspn for reasons I am about to describe. According to a KDC, while an SPN represents an actual service running on an actual machine having a host name in DNS which can be reached over TCP/IP, it doesn't actually have to be real at the time though. Here's why. Have you considered the case where perhaps the service, or even the machine it will be run on, will be installed later? The service and even the machine it is running on, and the DNS entry for said machine, doesn't have to be in place in the here and now when you create the SPN. Setspn.exe is simply a rudimentary tool which exists that allows you to create SPNs which will conform the RFCs for Kerberos. Its up to you to architect it right though, it's not going to hold anyone's hand in the process. I work for a large company and create SPNs all the time for services, and even for machines, which do not yet exist. That way the Developers or sys admins don't have to contact me to have an SPN created after the fact. They are following a project plan and savvy managers are going to have the SPN, DNS entires, IP addresses for machines, all planned out and created ahead of time before the OS admins get around to actually spinning up a live server for such use. So if setspn prevented people from creating an SPN for a service which is not yet up and running, there would be some very angry system admins out there. That is why it is allowed to create "invalid" SPNs, when you think it shouldn't. If you want something to do extra layers of validation not afforded by the generic setspn.exe, to catch mistakes before your application does, then you will have to create such a thing yourself. Ask yourself though, is this worth the time for something so specific? I mean, how often are you creating SPNs? This should all make sense to you now. I periodically run a setspn -X to catch duplicate sin my domain. I've never had the time, but I suppose I could also list out all the current SPNs in the domain and check if they are each currently valid, and take corrective action if they weren't. I'm sure there are probably more than a few which no longer are active. I don't consider it that big of a deal.
I am working on Mongodb authorization.
I added users and am using mongod --auth while connecting to the database so that only authorized users are able to see the database.
Right now, mongo db can only be able to access throught vpn.
Suppose if a hacker breaks into the server machine, he can close the existing mongod connection(which was running with security using --auth) and can start a new connection without authentication mode after which he can see all the data of the database.
How can we secure database so that everytime it asks for the username/password to be provided.
Or some other ways to prevent this.
Thanks.
If he breaks into the server machine, he won't restart mongo. He would simply copy the mongo database and open it on his own machine, without using mongo at all.
If the attacker has the control of a server running process P1, P2, ... each Pi has to be considered breached, including theirs data.
The exception is strong isolation (i.e. virtual machines) and crypto; if the application crypts all its data with a key whose generation is not fully automated (i.e. a passphrase to be inserted on the startup, a challenge/response the administrator needs to pass during the boot, etc ...) this may prevent the attacker from getting all the bits to decrypt it. Otherwise, if the application is able to encrypt and decrypt without any human help, the attacker is able to do it as well.
Those things do not apply to mongo, that does not have support for stuff like that. Good old SQLs have it but they are not trendy any more ;)
On the specific user: are you afraid they will break into as mongodb or as another user? Because if they get the user foo, they still may have problems in accessing mongodb (data or process) if local permissions are well set. But again, people tend to consider the local privilege escalation (i.e. moving from foo to root and then to mongodb) something that happens when someone breaches. In roughly 100 pentests I managed to get access to a machine, probably just once or twice I could not escalate.
My database is hosted in a shared hosting. I connect my database remotely in Management Studio Express. Whenever i try to connect to sqlserver instance it shows all the databases that are hosted in that server instance. This annoying to find out your database out of 400 database of the other users all the time.
Is there a any way to filter down the list of databases to those i won or have permission ? i don't want to see databases that i don't have permission or i don't own.
Remember my database is hosted in a shared hosting and as a user i have limited privilege.
I've researched a similar issue and the only method I've found that works for this is a little hackish, however it may work for you in this case. If you (or the administrator of your shared host) is able to make your login the DBO of your database, and then also DENY VIEW to all databases for your login, you should only see the database that your login owns when you connect. So the t-sql would be:
`USE AdventureWorks2008R2
ALTER AUTHORIZATION ON DATABASE::AdventureWorks2008R2 to TestLogin
USE MASTER
DENY VIEW ANY DATABASE TO TestLogin`
Not sure if this is a fit for your scenario, and definitely not saying it is a best practice, but maybe it helps!
I have created the solutio for this problem in SSMSBoost add-in for SSMS (I am the developer of this add-in).
There is a special "Smart connection switch" combobox on the toolbar, that you can configure to show your favorite connections (Preferred connections), also you can display all local databases, BUT only those, that you can access.
I'm confused about a point of pg_pool-II's documentation. The health_check_user is used to determine the health of DB cluster servers, but what abilities does the health_check_user need? As there are no configuration options to get a password for this user, I'm assuming that pg-pool's health_check_user will likewise need trust level access to each DB?
It looks like it just needs permission to connect to the databases (same username for all databases).
You don't need to rely on trust auth either, I'm sure you can use a .pgpass file.
http://www.postgresql.org/docs/9.0/static/libpq-pgpass.html
As Richard said, it only needs to connect to the database.
And also you can set password for this user with health_check_password