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($开发者_StackOverflowSuperSecure[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);
精彩评论