I've created a PHP script that will run on client computers to act as a bridge between a merchant app running on those computers and their e-comm websites. Basically, the usage of the script isn't even important in my question.
So the script will be distributed as an ionCube'd file, that will need to be accompanied by an .ini file that will contain in plain text 3 1 constants. Let's say DB_SERVER (something like LAPTOP-AF16CB28), DB_USER (a username for the MSSQL Server connection), a DB_PASS (the password), and lastly KEY that will be created by me before distribution, based on some logic in relation to the other 3 params...
The idea is to check the 4 constants internally in the encoded file, before execution, and if the 4th one matches the logic I'll be using on my end to create it based on the other 3, it'll run...
Can you give me some ideas for an exotic logic behind that string manipulation? It has to be something not easily guessable...
Something like md5(md5(DB_SERVER).md5(DB_USER).md5(DB_PASS).$some_standard_salt), but preferably a bit more exotic... I know that the use of a pre-determined salt word, already makes it virtually impossible for others to guess it, but I'd just want your opinion on the matter.
CodePudding user response:
Here is a bit more exotic solution using openssl. That should even defend you against someone figuring out how the key is derived. But without your private key, they can't generate a key themselves.
First we create a private key using openssl.
openssl ecparam -name secp112r2 -genkey -noout -out key.pem
That results in file key.pem. That's the file you have to keep secret. We choose secp112r2 so that we could get reasonably short signature.
We also have to generate a public key for validating the signature later.
openssl ec -in key.pem -pubout -out public.pem
That results in a file public.pem. We can add the contents of that to our php code.
Now for the key generation. Let's say our parameters are following
DB_SERVER = 'LAPTOP-AF16CB28'
DB_USER = 'Username'
DB_PASS = 'Password'
We are just going to concatenate these and sign the resulting string with our private key. We are also going to convert it to base64, that's our KEY.
# echo -n is need so that \n wouldn't be signed
# -sha1 is default hash in openssl_verify, so we are going to use that
echo -n LAPTOP-AF16CB28UsernamePassword | openssl dgst -sha1 -sign key.pem | base64
#Result: MCACDh5l/ffxXOrM3yOkp Z7Ag4NXrm0wpVYtLKoVyDUSA==
And in our PHP code we can make use of it like so. Even if all of the following code would be public no one could generate a KEY that would be valid for that public key unless they have your private key.
$DB_SERVER = 'LAPTOP-AF16CB28';
$DB_USER = 'Username';
$DB_PASS = 'Password';
$KEY = 'MCACDh5l/ffxXOrM3yOkp Z7Ag4NXrm0wpVYtLKoVyDUSA==';
// The public key. Contents from generated public.pem
$public_key = <<<KEY
-----BEGIN PUBLIC KEY-----
MDIwEAYHKoZIzj0CAQYFK4EEAAcDHgAExGBqNPovZjCPa3s/iQIprtX7uLJsfDUl
5SVHwg==
-----END PUBLIC KEY-----
KEY;
// Must match the data that was signed
$signed_data = $DB_SERVER.$DB_USER.$DB_PASS;
// As we encoded the signature to base64, we have to decode it now
$decoded_key = base64_decode($KEY);
$verify = openssl_verify($signed_data, $decoded_key, $public_key);
if ($verify === 1) {
echo "Valid key";
} elseif ($verify === 0) {
echo "Invalid key";
} else {
echo "Error";
}
Answers to questions in comments.
- Only thing you need to generate for every client is the signature/key. Public key can be just distributed in the source as heredoc, that’s what’s used to validate the key.
echo string -> string\n; echo string -> string. That just means that without -n you’d have to verify a string later that also has a trailing newline. I don’t have a good way to store it in a var right now. Generating the key on the command line to give it to the client seems okay to me.if ($verify === 0) { exit; }should bey fine.
