How should I store a AES Encryption Key? - php

I run a DV 3.5 server on MediaTemple with Linux CentOS 5, php and mysql DB and am trying to encrypt phone records with AES.
I came across what seems to be good script as PHPAES
but I am not sure of the following:
Where do I actually store the AES
Encryption key used to encrypt and
decrypt the phone number?
How do I call on the AES encryption
key when a user submits their data
via form and stores into our MySQL
database?
When I want to descrypt that information for our internal customer service agents - how do they in turn call on the AES key?
I realize this is probably very simple but please don't insult. I am trying to learn best practice for how to move forward with any type of encryption whatsoever. Something (to this point) we have not had need for.

I have developed a process where I start with an initial encryption key that I encode into a SHA1 hash, then encrypt using a with a username/password combination and store it in a database. The password (hashed or otherwise) is never stored in the database and is only used at login to decrypt the encryption key. I then use that master username/password to create additional users with passwords in which a PHP or JavaScript encodes the decryption key with the username/password of the new user and stores that encrypted key in the database. When I attempt to decrypt the encryption key from the database using a username/password combination I should expect a SHA1 hash back. If I do not get a valid SHA1 hash back that can decrypt data, then I know the password is wrong and the data is unusable. You must have a valid username/password combination to get the decryption key and that is transmitted to the client via SSL, decrypted using a JavaScript function, then stored in a cookie for the SSL session.
To circumvent the system, decrypt the data and access the information you'd have to be infected with a key-logger or trojan that scoured you cookies during that login session, otherwise the server owner nor a client without the username/password combination can use the data in the database without brute forcing it. Using AES 256-bit and strong passwords (12+ characters, A-Z, a-z, 0-9, symbols, etc) and you've got yourself a fairly difficult to breach solution, or at least one that would be painful to attempt.
Each account has a lockout feature, so if you try to login via the web too many times and fail, the account is locked out. All PHP pages encode/decode parameters to prevent SQL injection attacks and validate a PHP session is active and matches the last session tracked during you login, and also validates your encryption key works. Each time you login or visit the login page, the previous session is invalidated or if your session times out it is also invalidated. Even with all those layers its fast and prevents people from using PHP scripts that output JSON using fabricated POSTs to scripts and SQL injection attacks. It also limits the ability for the server owner/administrator to decrypt and read your information if its stored on a shared provider, etc.

I actually ended up going this route:
I encrypt the initial data with a salted hash which is stored in the database itself (and is unique to every record stored). I then take that 256bit AES encrypted string and run it through RSA encryption with my public key which sits server side.
in order to decrypt, I have to upload a temporary file with my private key and retrieve the necessary data.
quite secure in my opinion.

Related

Why does Laravel change the value of cookie for every request?

I understand that the session_id need to be regenerated after user login to prevent session fixation attack. And the session_id need to be a random string to prevent attacked to brute force it.
So Laravel need something to encrypt the session_id.
But why Laravel choose encryption over hashing for session_id?
I check the documentation that Laravel use AES encryption for session.
But still, Why Laravel choose an encryption method that produces a different value every time after session_id being encrypted?
What is wrong with the encryption method that produces a fixed value for session_id, and then set it for that cookie?
Why the cookie value of the session_id is changed every time for a new request?
I accepted Danyal Sandeelo's answer.
The value of the cookie is encrypted,
which contains 2 things--session_id and the HMAC hashed string.
The HMAC-hashed string is hashed on the server using APP_KEY:
HMAC(the session_id, the APP_KEY ). Then the server use AES to encrypt it and send it to the client side.
AES encryption produces different ciphertexts even with the same plaintext using the same key.
When the encrypted value of cookie is sent back to the backend,
the server will first decrypt it to get the session_id and the HMAC hashed string.
Then it will use the APP_KEY to HMAC-hash session_id to see the outcome value match the return HMAC hashed string or not.
If it didn't match, then that means the session_id is tampered by the client side.
And the value of session cookie is changed for every request, it is because AES encryption produces different ciphertexts even with the same plaintext using the same key.
The question is not just related to Laravel but it's more like Dynamic encryption vs Static encryption irrespective of language and framework.
You can encrypt a value but you can't de-hash a hash value. As the data is going to be used later on, we keep it encrypted so that it can be de-crypted later on.
Dynamic Encryption provides extra protection, as not only the encryption keys but also the configuration of the crypto system change for each data transfer. The inner encryption algorithm (e.g. AES-256 or national algorithm) is wrapped by an outer Dynamic Encryption algorithm. When the data transfer is complete, the encryption algorithm is discarded, which leaves no way of introducing master keys for data inspection.
Cryptanalysis (code breaking) normally requires large amounts of data to be encrypted with the same method. As Dynamic Encryption is constantly mutating, cryptanalysis is made practically impossible.
Here is a good read about why dynamic encryption is being used.
The driver used matters here.
The cookie driver stores all information inside the cookie and thus Laravel needs to be able to decrypt that value to read it and the value changes every time because the session is modified each request resulting in different data being encrypted and thus the encrypted string you see in the cookie is different each request.
However when using the file driver (or any other driver than file or array) Laravel still needs to be able to read the plain text session ID (so encryption not hashing) to look it up in the data store but stores the data in a file/database/redis which should keep the cookie value the same for the duration of the session since the session ID doesn't change.
Read more about all the drivers and where the data is stored in de documentation.
Laravel changes it Because of privacy.....

How to securely store multiple passwords on behalf of a user for external applications?

I'm building a web service and one of the included features involves storing passwords and credentials for users external applications.
My app is built using PHP/Laravel, the current security measures I've implemented are:
Email and password login accompanied by compulsory two-factor authentication using Google Authenticator
Once users are in they need to type in again a master password to access their database of credentials for their external applications.
CSRF Protection and SSL
The passwords are stored in a MySQL database and encrypted using Laravel's encrypt() method and only decrypted (using the decrypt() method) and given to the user if the authenticated users session ID matches the ID in the row with the password credentials.
When a user requests a password credential is it pulled from the database using AJAX, decrypted and copied to the clipboard then deleted from the client side using javascript so the password is only available for a few seconds on the client side before it's back only in the database encrypted as it was before.
Edit: The key for encryption and decryption is Laravel's app key which is a single key stored in the environment file outside of the visible server files in the public folder.
My application is B2B SaaS and is used by mid-large sized clients meaning it needs to be secure. Please point out any flaws you see in my method or any other advice you think is relevant thanks.
The best way to do this is to not do it.
Put another way: If you can get away with not storing passwords (i.e. using OAuth2 instead), don't store passwords. You don't want the extra liability.
That being said, sometimes you literally cannot avoid storing passwords (e.g. IMAP integrations). In this case, always start with a threat model before you delve too far into the weeds.
If someone hacks your database (e.g. SQL injection), what can they access?
Can they access the filesystem and read the encryption keys?
Can they rewrite ciphertexts from a targeted user's account into the field for an account they already hace access to, and thereby gain access to the plaintext without first obtaining the encryption key?
When a user requests a password credential is it pulled from the database using AJAX, decrypted and copied to the clipboard then deleted from the client side using javascript so the password is only available for a few seconds on the client side before it's back only in the database encrypted as it was before.
It sounds like you're reimplementing a password manager. You might want to shepherd your customers towards something like KeePassXC or 1Password instead.
Since this decryption doesn't include any user-provided secrets, the webserver must therefore be capable of decrypting all of your users' passwords. So if an attacker can hack the webserver, they get all of the users' passwords for free.
If you're dead set on partially reinventing password managers, you're going to want to embrace the principle of least authority and make your server unable to decrypt your users' passwords.
This means using client-side encryption, where your server is a black box that only stores ciphertext.

Using password as part of encryption key in Mobile - Server communication

I am currently working on a mobile app that has a accompanying web service being developed in PHP. The one thing that we want to make sure is that the users data is safe in every possible way.
After careful evaluation, we have decided to use RNCryptor for all things related to encryption. This is in addition to the HTTPS connection. The current process is like below (login example):
The RNCryptor library on iOS uses a key to encrypt password before sending it to the server.
The server then stores this encrypted password on the database.
While re-authneticating, the app sends the password (again encrypted with the static key) and the server decrypts it (means the server also has the encryption key), verifies the login and sends the login key (encrypted with the same static key) back to the client.
Every subsequent request relies on the encrypted loginKey and the username for authenticating the validity of the user and login session.
I believe the above system is flawed because of the STATIC encryption keys and since the key is available on both the server and the client.
What we would like is to make the encryption key dynamic by merging the raw password with the STATIC encryption key. This would make encryption key unique for each user but it also means the server will have no idea about the key. It is essential for the server to know the key since other user data also gets encrypted and decrypted based on this key.
Can somebody help me out with this? What steps do I need to take to make the system more secure? Any code snippet or reference link specific to server-mobile client would also do. I know there are a lot of tutorials out there but mostly all resume the client to web based and not mobile.
PS: Sorry for such a long post.
I would probably just use OATH2 tokens for authentication, but if you wanted to do it your own way...
For securing passwords a salted hash is used. As a basic example of hashing passwords with a salt consider the following, and keep in mind it's NOT cryptographically secure.
shaResult = SHA1(16 Byte Random Salt | "p#ssword")
Basics: The server stores the shaResult. Your app stores the salt value generated. When the user types in their password you append it to the stored salt, hash it, and send it to the server for verification. There's really no need to encrypt it to the server now. The HTTPS connection should handle that.
Good cryptographic password hashing is described in detail at Salted Password Hashing - Doing it Right To summarize they suggest using the following:
Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). Suggested CSPRNGs is given in the link for multiple programming/scripting languages.
The salt needs to be unique per-user per-password. Every time a user creates an account or changes their password, the password should be hashed using a new random salt. Never reuse a salt. The salt also needs to be long, so that there are many possible salts. As a rule of thumb, make your salt is at least as long as the hash function's output. The salt should be stored in the user account table alongside the hash.
Use a well-tested cryptographic hash algorithm, such as SHA256, SHA512, RipeMD, WHIRLPOOL, SHA3, etc.
Use slow hashing functions that perform multiple iterations. Standard algorithms include PBKDF2 and bcrypt.
Use a keyed hashing algorithm, HMAC.
I'll reiterate that secure connections still need to be used in conjunction with the above.
If you want a method that does not use the same authentication value each time consider using the Challenge-Handshake Authentication Protocol which protects against replay attacks. See RFC1994 for more complete details.
At setup a shared key is established between the client and server. This must be done securely, possible with SSL or side-channed communications.
Authentication:
The server sends a random challenge to the client.
The client uses the challenge value to compute a hash with a function such as PBKDF2 and sends it to the server along with the user identifier.
The server performs the same computation and verifies the value from it's user identifier/shared key table.
There are slight variations but the concept is the same.

Passing URL parameters with PHP

I am creating a program that communicates with a PHP script on a web server and to do so I need to be able to pass parameters from the program to the PHP script.
Now here is my question. At some point the user name and password needs to be passed to the script. Now this is not done in a way that is apparent to users (such as in an address bar) but I know with a little sniffing around someone that really wanted to could figure it out. So while my script is safe from injection, obviously variable tampering is an issue here.
This is an idea I have come up with so please help me wrap my head around it and see if this would work the way I THINK it will.
My thought was to encrypt the user password (or another unique key) variables on the client side before sending so you get a url like (obviously just made up) mypage.php?un=Oa348uty8&ps=op986hGTfreu Then when it gets to the PHP script decrypt it and encrypt it again with a different salt.
So when it leaves the application it would be encrypted but not the correct way, and then when it hits the PHP script server side decrypt it and re-encrypt it with the correct salt so it would correctly match the stored encrypted password.
This way, they user would not know what the encrypted version of their password is supposed to look like so without that they would not be able to tamper with the URL and try to insert fake values.
To put it in a nutshell, you are thinking of this:
On server side you have:
a database, with login/password matches.
a script that take 2 parameters (password and username) and check in the database if the couple exists
Your problem:
When your local application call the php script on server side, the 2 parameters are given in plain text. And you want to avoid tampering ( if your script are safe against injection i only see tampering used to bruteforce the auth <= keep in mind that i will keep this assumption in the whole post)
Your solution:
On client side, encrypt the 2 parameters
On server side, add a salt in your script to salt
Then decrypt the 2 parameters and encrypt with a salt
What I think:
This will not solve the tampering issue, someone can still forge requests.
The first encryption is useless because someone can retreive the key used by your client.
The second encryption is not safe enought because you use the same salt for all you users.
What I suggest:
Accept that tampering can't be avoided if you don't use a secure protocol like HTTPS (can either use SSL or TLS).
If you want an acceptable security without HTTPS the following is what i would implement:
A token system that you will check in order to see if the user can perform the login operation
A username that would not be encrypted
The password sha1 hashed stored in database
On client side, you call the script and provide the username as non encrypted and your password as a sha1 hash, rehashed with a random salt (sha1(sha1(pass)+salt) (the salt is stored in the user session on server side)
The script would then compared the provided hash with db password hash rehashed with session salt
The improvement is that the attacker must try to brute force two sha1 passwords consecutivaly and must provide a valid token to perform the login action. Plus if you use as salt a string using hex char of a variable even length, it will make the job harder for the attacker to recognised that the value bruteforced by the second hash is a sha1 hash, and even if he know it's an sha1 he will have to test multiple case to try to find the right portion of the value that correspond to the hash.
Because of variable salt, a same password won't be the same if hashed:
Imagine the attacker sniffed a hash and know which password was used then sniff another hash that was made with the same password as the other, the attacker won't be able to know that the 2 password where the same( a little overkill but still usefull).
It is safer to store the password as hashed value, because if the attacker manage to dump your user table, he won't be able to use the passwords right away, he would have to bruteforce each of then.
Finally sha1 hash are safer than md5 (i tell you that because you used the md5 tag in your post)
The downside of this method is that passwords can't be reversed, so you won't be able to given them back to your users if they lost it. You will have to make them set a new one.
An hardcore way (still without using HTTPS), would be to encrypt your password and username with a strong cypher (like AES or 3DES) and use a secure key echange algorythm (like the Diffie Hellman one) to exchange a random shared key.
This method won't block tampering, but will screw the attacker, because he won't be able to decrypt the value (assuming he only is sniffing the network). The key is random and never hardcoded in any of your application, so even if someone reverse your client, he won't be able to retreive a key.
I would still recommend to store your password value has hash.
An extreme way would be to merge the 2 methods but would be completly overkill.
Hope this will give you ideas
The problem with your approach isn't whether you are using encrpyted passwords and usernames in the URL or not. If the user authenticates by sending the encrpyted strings to you, then I as an attacker can still sniff out those hashes, pass them to your application and authenticate. This is unless then, that you do some public key/private key exchange before hand, but that is just reimplementing HTTPS, so you might as well just use HTTPS.
What you should do is to send the request using POST over HTTPS.
POST: So that the authentication details will not be in the URL and show up in logs and referrer URLs.
HTTPS so that the content of the whole request is fully encrypted and can only be decrypted by the client application and the server side.
encryption with Javascript from client to server only prevent from non SSL posting fails.
I think you must use sessions instead of this type encryption .
Update:
You could add your own secret key in both scripts.

Secure password encryption/decryption of strings in PHP

I wanted to know if there exists a somewhat simple, but secure, method to encrypt strings(not passwords), with a password which is not stored on the server, in PHP.
I've checked A reversible password encryption routine for PHP, but I'm unsure if it is secure enough if intruders have access to the server and source.
We're talking about a automatic system where a computer sends a request to a server, which stores information in a log. So I'm thinking I could send the encryption password in the request header, preferably encrypted, but then it would be difficult to decrypt without storing the password somehow on the server. Wait, I think i might be complicating things a bit too much, but I hope you get the idea... It's meant to keep the information safe, even if hackers have full control over the server.
If I understand you correctly, you aim for a log that is encrypted by the server. The requests are sent in plain, but you'd like to log something like per-user access statistics or the like and you deem this data to be confidential, so it should be encrypted by the server and also be decrypted by the server, if necessary.
If this is the case, it is actually not all too complicated.
Generate an encryption key (AES would be a good choice) that is to be used by the server.
You store this key in a file.
Make sure that the application and only a few selected people have access to that location. Worst case would be it's served in your public files and anyone could download it from the web. So put it in a folder far away from your public resources :)
Encrypt that file using password-based encryption e.g. PBKDF2 in RFC 2898.
Then you will realize that you created a hen-egg problem - the file again needs a password for the server to have access to the key stored inside. But here's the trick - you will have to enter the key upon server startup manually, and that's the ephemeral component you need. The password for the file should be out-of-band information (e.g. placed in a physical vault) and nowhere on the computer itself.
An alternative (but potentially less secure because the password would be present in some physical form) is to rely on OS-specific "password vaults" such as Windows' Isolated Storage.
One option for this, which would seem to meet your requirements, would be to use public/private key cryptography. If you had the user encrypt the string using a public key then had the encrypted data stored on the server it would not be possible for an attacker to decrypt the data.
when/if you need to decrypt the data just copy it to a location where you have the private key and use that for decryption.
I would go with Mcrypt to encrypt/decrypt data in php.
My algorithm of choice would be twofish.
You will need a key to encrypt/decrypt data and sending it via request could be a security issue unless you have ssl implemented.
If the encryption should be on request not real-time thing than you could just execute the script in console so the password is not stored on the server.
The code for encryption/decryption is simple:
$encrypted= mcrypt_ecb(MCRYPT_TWOFISH, $key, $input, MCRYPT_ENCRYPT);
$decrypted= mcrypt_decrypt(MCRYPT_TWOFISH , $key, $data, MCRYPT_DECRYPT);

Categories