encrypt password in a text file - php

I am defining my database in the php file
define ('DB_HOSTNAME', 'localhost');
define ('DB_USERNAME', 'user');
define ('DB_PASSWORD', 'pass');
define ('DB_DATABASE', 'dbase');
Is there a built in way I can store an encrypted / hashed password in a text file and then de encrypt it in the program rather than storing my password in my source code.

I back up my source codes to repository thats accessible to lots of people.. beyond my group too..
Then what you want is to separate the sensitive configuration from the source code. Don't check it into the repository, keep it in a protected file somewhere on trusted computers and only deploy it to the production server separately from the code.

Related

Is this a good enough way to "hide" the db credentials?

Just looking for some tips if this is good enough or if i should do anything different to "hide" my database credentials. Been searching for a long time. I have found alot of ways to do this and feel everyone does it a different way. So wondering if this is good enough. Thank you.
Right now I'm storing a config.ini file with my database credentials outside of the public directory.
Then inside the public directory I got a folder name db_includes. This is where i have my db connection php file. This is the code for the database connection.
$config = parse_ini_file('../../private/config.ini');
$db = new \PDO('mysql:dbname='.$config['DB_NAME'].';host='.$config['DB_SERVER'].';charset=utf8mb4', ''.$config['DB_USERNAME'].'', ''.$config['DB_PWD'].'');
Also inside the db_includes folder i got a .htaccess file that has "deny from all" so its not possible to get to that db_includes folder or the database connection file.
Is this good or should i also move the database connection file outside of the public directory and just call it when i need it?
There's a few ways of doing it. First, I recommend using a PHP file to store the credentials, this way if your htaccess fails, the php file will be parsed anyway and your credentials won't appear:
config.php:
<?php
return [
"DB_NAME" => "database",
"DB_USER" => "user"
// ...
];
Wherever you need:
$config = require "path/to/config.php";
$db = new \PDO('mysql:dbname='.$config['DB_NAME'].';host='.$config['DB_SERVER'].';charset=utf8mb4', ''.$config['DB_USERNAME'].'', ''.$config['DB_PWD'].'');
If possible, keep it outside your public folder as it is a good way to make it safe.
Remember that if your database and server is well configured and safe enough you don't need to worry about database credentials.

Magento - Using custom Environment Variables for sensitive database info

I know Magento stores the database connection details within the local.xml file, however our firm is trying to avoid passwords and other sensitive data being stored within our git repo's for security purposes.
I know you can create Environment Variables easily via an .htaccess file, but I'm hoping to find a workable solution that will enable me to set this database information dynamically from a environment variable.
As the local.xml is an XML file and as this is a non dynamic/server-side filetype we cannot use it to read environment variables.
Would there be a way to somehow add in some hook/custom behaviour to Magento in which I could replace the local.xml with a PHP file that will allow me to pull in these environment variables?
So in a sense, the local.XML would become a local.PHP file with the ability to read my own custom environment variables such DB_HOST, DB_USERNAME, DB_PASSWORD rather than having them already set in the xml file as localhost, root, password123 etc.
Any ideas on how best to achieve this, or are there any existing Magento add-ons/extensions/mods that will allow me to do this?
I would suggest git ignore your local.xml and dynamically create it with your deploy script. your deploy script should have your sensitive data variables.
I found an alternative solution to the problem. I extended Mage_Core_Model_Config_Element and overrode the 'xmlentities' function to check if the configuration value it is returning starts with a dollar sign, and if so substitute it with the equivalent environment variable.
If it helps anyone else, here it is...
https://github.com/rossigee/magento-config-envvars
Please try this solution:
copy app/code/core/Mage/Core/Model/App.php to app/code/local/Mage/Core/Model/App.php and replace the _initBaseConfig() method with the following one:
protected function _initBaseConfig()
{
Varien_Profiler::start('mage::app::init::system_config');
$this->_config->loadBase();
/* Read DB connection config from environment variables */
$connection = $this->_config->getNode('global/resources/default_setup/connection');
$connection->setNode('host', $_ENV['DB_HOST']);
$connection->setNode('username', $_ENV['DB_USERNAME']);
$connection->setNode('password', $_ENV['DB_PASSWORD']);
Varien_Profiler::stop('mage::app::init::system_config');
return $this;
}
This must help.
* EDIT
protected function _initBaseConfig()
{
Varien_Profiler::start('mage::app::init::system_config');
$this->_config->loadBase();
/* Read DB connection config from environment variables */
$this->_config->getNode('global/resources/default_setup/connection')
->setNode('host', $_ENV['DB_HOST'])
->setNode('username', $_ENV['DB_USERNAME'])
->setNode('password', $_ENV['DB_PASSWORD']);
Varien_Profiler::stop('mage::app::init::system_config');
return $this;
}
Have you considered simply adding local.xml to .gitignore and creating/updating it as part of your deployment process? Note that local.xml typically stores more than just database credentials. For example, it might also store the configuration for the caching backend(s) as and session storage. These are usually also server specific, and will make things very messy if you try to avoid using local.xml.

Where to put database connection settings?

Where do you put the connection settings for a database connection (things like host, dbname, user, password)? Is it placed in the database class or file, or outside in a config file, or somewhere else?
Ideally, you should place it in a config file, which can be something as simple as a PHP array.
For example: db_config.php
$db_config = array(
'host' => 'localhost',
'user' => 'username',
'password' => 'qwerty'
);
You should then place this file outside your document root for maximum security. This way, if your webhost fails you and begins serving PHP files as text files (happens), no one can get your DB credentials.
It can be done in many ways, but what is common is to put it in a settings file, and keep that file outside of the webroot, so that information about the database password can not accidentally leak into the web.
For PostgreSQL, I really like to use pg_service.conf. It allows me to put all connection specific settings (hostname, database name, username, password, etc) into ~/.pg_service.conf or to /etc/postgresql-common/pg_service.conf and give them common name (service name).
Now, any program (Perl, PHP, etc) that wants to connect to database can simply specify "service=name" as their connection string - nice, clean, secure and easily maintainable.
As far as I know, MySQL has similar mechanism for ~/my.cnf or /etc/my.cnf files - you may want to look into that.
There are a lot of ways doing it, but I do it this way by defining CONSTANTS:
Create a config/db.php
<?php
define('DB_INFO','mysql:host=localhost;dbname=test');
define('DB_USER','root');
define('DB_PASS','');

Is my method for protecting MySQL DB password secure?

When using:
$con = mysql_connect('localhost','user','password')
I have read about the benefits of storing the password part elsewhere (https://stackoverflow.com/a/3354457/1704651).
I'm fairly new to PHP and want to know if my method of storing MySQL passwords is secure:
Step one, choose a lengthy MySQL Database Password (https://www.random.org/passwords/?num=1&len=24&format=html&rnd=new)
Step two, put this in /outsidewebroot/salt.php (my actual salt is longer)
<?php $salt = sdcjbdt8veADJbyuQxsfJtYeW7tC5; ?>
Step three, encode password using a temporary PHP file (which is deleted after use):
$decrypted = "my decrypted MySQL password"
$key = $salt;
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $decrypted, MCRYPT_MODE_CBC, md5(md5($key))));
var_dump($encrypted);
Step four, put this code in .htaccess
SetEnv encrypted-password i3NOByNkztBtEbJ8LJMt2GbX9VjMzO2MTYtBXsxyYVI=
Step five, put this code where you need to connect to your database:
require_once("../../outside-webroot/salt.php")
$key = $salt
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted-password), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
$con = mysql_connect('localhost','user',$decrypted)
The salt in /outsidewebroot/salt.php is the same one that I use for hashing passwords in my database so I only have to include it once for two uses.
The encrypt/decrypt method I saw here: http://ideone.com/yQIAX
I have also seen this method: https://stackoverflow.com/a/3354457/1704651 using a hash instead of the encrypt/decrypt method.
Thank you for your feedback on my method.
No. If someone can get your files or run programs it's game over:
If your web directory is writable, I can simply add a line echo $decrypted; above that mysql_connect() and get the password.
I can copy your files down and edit them there.
Security is a process that you go through, not some library you can link into your program.
You should store the configuration in the php.ini file so that your program need only mysql_connect() (with no arguments). This is a good idea because it may be easier for an attacker to convince your system to print out source code and web-accessible files than print arbitrary fiels on your system.
On Unixish systems like OSX and Linux, you should make sure you're using unix domain sockets which do not expose your MySQL server to the Internet; someone cannot connect to your MySQL server if it is not on the Internet. This provides some further protection against the "get your files" attack.
Take care to not permit your web users to create php files (or anything else executable). This provides some protection against the "run programs" attack,
If I can upload/edit your files, I can do anything they can do, so you should also be careful about your GRANT statements that you put in your MySQL server: If only the administrator needs to do certain INSERT or DELETE to certain tables, consider running the admin scripts as a separate web-user with separate rights. If your scripts cannot delete all your data, then I as an attacker cannot either.
The first rule of security is that if you're not certain you're secure, then you probably aren't.
The next version of PHP (v5.5) will have a set of functions built-in that provide standardised password hashing. Once this version is released, that will be the only recommended way to handle passwords.
In the meanwhile, you can download a compatibility library that implements the same functions for current PHP versions. Download it from here: https://github.com/ircmaxell/password_compat
See also: http://www.h-online.com/open/news/item/PHP-5-5-should-reduce-password-sloppiness-1707835.html for reference.

How to encrypt mysql password in php (or how to defeat automated code scanner red flag)

Management strikes again.
How should I satisfy the code scanner that is going to read my php source and red flag my MySQL connection string?
Linux Server (soon to be Sun)
php 4.2 (soon to be latest version)
MySQL database
Servers in a DMZ outside of the firewall
Read only MySQL account
Not a single byte of non public information in the database
I have to encrypt my MySQL password in the connection string for no reason other than it is going to be red flagged by the automatic code testing solution. Management is enthralled with the concept of Pen Testing without understanding it.
I know full well it isn't any more secure to encrypt the password in the file with all the other measures in place, but my sites will be taken down if I don't comply. I know it hurts performance but this site isn't so popular, and isn't a huge database driven app anyway.
My attempt:
//encrypt and decrypt are functions I stole wholesale off of the php.net manual
...
$SuperSecure[0] = array(encrypt("test"), encrypt("test")); //dev
...
$dbcnx = mysql_connect('localhost', decrypt($SuperSecure[0][0]), decrypt($SuperSecure[0][1]));
Is there a better way? More importantly, am I missing something and this is actually necessary?
Edit: I can't fight national anymore. If I ignore this directive my site comes down and losing my job over this is dumb. I just to do this as easily (and with the least performance impact) as possible.
If you don't want to write the password directly into mysql_connect, why not write something like:
$username = 'test';
$password = 'test';
mysql_connect('localhost', $username, $password);
Without knowing how clever the scanner is you won't really be able to tell what obsfucation is enough to not raise any flags.
You can use rot13 to obfuscate (not encrypt) the password
Couldn't you define the default mysql host, username, and password in a php.ini file? Then the mysql_connect function looks like:
`mysql_connect();`
And unless a hacker has your php.ini file, they won't be able to access the username or password. Even if they changed the function to echo. Sure they could echo the directives, but I think it is obfuscated enough, as the password could not be found in any of the source files, aside from php.ini, which is a server-file.
Given, if someone did a phpinfo(); it also would be displayed in plain site, but it would still work.
This solution is very similar to the ODBC solution provided by another answer. It also has the flaw that if the scanner checks your php.ini file, it is going to end up red flagging that instead.
If you would like to make fun of it at the same time, I'd suggest randomly putting snippets of your mysql code in random files that are all includes before you need to connect. AKA
Index.php
Global $password;
$password = "S";
RandomFile.php
Global $password;
$password .= "T";
RandomFile2.php
Global $password;
$password .= "A";
RandomFile3.php
Global $password;
$password .= "CK";
RandomFile4.php
Global $password;
mysql_connect($host, $username, $password."Overflow");
XOR! The basis of the venerable one-time pad. It's legitimate encryption, makes you look more suave then rot13() and anybody competent should be able to figure it out. At the same time, nobody will be grepping your password.
<?
$pass = 'foobar';
$key = 'monkey';
$secret = $pass XOR $key;
$list = array($key, $secret);
foreach($list as $x) {
print "Keypart: ";
print implode(unpack('H*',$x));
print "\n";
}
?>
Aaand I suddenly hate how PHP does arrays... Now, take the output of that...
<?
#Keypart: 6d6f6e6b6579
#Keypart: 666f6f626172
$secret = '666f6f626172';
$key = '6d6f6e6b6579';
$pass = pack('H*', $key) XOR pack('H*', $secret);
print "$pass\n";
?>
The first part is your encryption generator, and the second part is what you have to put in the program. The only rule is that whatever bytestring you XOR the password against should be the same length as the password. It probably won't do anything unwanted if it isn't, but I don't feel like building a testcase.
It IS unnecessary, since you'll just obfuscate the password. Anyone who has the source could log in to the database since your PHP script has to know decrypt to get the original password.
Example
let's say that your password is a number, for example 42 and that encrypt is a function which multiplies by two and decrypt does the opposite.
Then, you'll store 84 in the code somewhere. However, PHP has to know the decrypt function also and will convert it to 42 first before connecting to the database. So, since everything you need has to stand in the PHP file, it is pointless to obfuscate the necessary information.
Some evil hacker which has your source could always replace the mysql_connect in your code example with an echo and will get the plain text password...
Easy obfuscation
Maybe it suffices to use something like "t"."e"."s"."t" instead of "test" in your code to bypass detection of the password...
You could use an ODBC connection to access the database. The ODBC abstraction layer stores its connection properties in a separate file (in UnixODBC, it's /etc/odbc.ini and ~/.odbc.ini). That way, the system DSN can know how to access the database, and your script will rely on it.
I'd advise caution in using ODBC, though, as it doesn't have access to some of the more complicated functions and queries that a straight MySQL connection does.
I might be missing the point here, but let me ask this.
Why are you not storing your mysql connection information in some form of config file, that is included at run time, and using some form of database abstraction, rather then peppering your code with mysql_connects and other legacy methods of dealing with database connections?
I would find it doubtful that your automated code scanning solution would read plaintext ini files, or xml ini files, and some frameworks, Like Zend, make it very easy to deal with these types of configuration files, so that your password is not scattered throught your code, or web accessible at any point...
It sounds like you have all the other measures in place(server outside of network, secure mysql account with only the needed privs.). Am I misconstruing what you are doing, or is there a reason to avoid the best practices here?
Regards
Been using Windows as server from day 1 and dunno whether my way has been wrong from the start, but storing credentials in registry (and reading from it) works and I've been doing it this way.
Here's my snippet:
$Root = HKEY_CURRENT_USER;
$key = "Software\MyApp1";
if (!($registry = #reg_open_key($Root, $key))) {
throw new Exception("Valid Credential not found.");
}else{
$user = reg_enum_key($registry, 0);
$passw = reg_enum_key($registry, 1);
}
reg_close_key($registry);

Categories