can we rely on laravel encryption for future? - php

We are building application where we need to store a data encrypted in database and instead of using MySql AES_ENCRYPT and AES_DECRYPT we are plaining to use laravel's inbuilt encrypt & decrypt functions.
Is it will be future proof as we don't want to loose data for future updates.

First of all, nothing is truly "future proof." In fact, we're on the verge of current encryption being rendered obsolete by quantum computing, making all current encryption methods very much not future proof.
Does Taylor have any plans of changing it in the foreseeable future? Maybe, maybe not, but the only real way of knowing is to ask him directly. He's quite active on Twitter and in other venues, so as far as business owners go, he's pretty approachable. He's also a generally nice person, so don't be afraid to ping him.
But let's take a look at the code:
public function encrypt($value, $serialize = true)
{
$iv = random_bytes(16);
// First we will encrypt the value using OpenSSL. After this is encrypted we
// will proceed to calculating a MAC for the encrypted value so that this
// value can be verified later as not having been changed by the users.
$value = \openssl_encrypt(
$serialize ? serialize($value) : $value,
$this->cipher, $this->key, 0, $iv
);
if ($value === false) {
throw new EncryptException('Could not encrypt the data.');
}
// Once we get the encrypted value we'll go ahead and base64_encode the input
// vector and create the MAC for the encrypted value so we can then verify
// its authenticity. Then, we'll JSON the data into the "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
$json = json_encode(compact('iv', 'value', 'mac'));
if (! is_string($json)) {
throw new EncryptException('Could not encrypt the data.');
}
return base64_encode($json);
}
That's the main encrypt() function from master in the repository, and from the looks of it, it's not likely to be changed too much without completely rewriting it. And while Laravel doesn't really follow the SemVer versioning spec, it does generally follow an internally consistent versioning scheme, making the most likely times for it to change are at the whole number and first-decimal change (i.e. - 5.4 to 5.5 or 5.5 to 6.0).
However, it's worth noting that it's actually accessed via contracts and the service provider pattern (so the only time the class is actually directly referenced is in its associated ServiceProvider class). This means that you can use this one for now and if a breaking change is introduced in the future, you can copy this version into your own encryption class, replace the reference in config/app.php to Illuminate\Encryption\EncryptionServiceProvider to your new encryption service provider, and you've now preserved that method and can use it throughout your application, without making any other changes to your application.
On a bit of a side note, you can also consider writing an "encryption converter" if you find you do need to change algorithms (such as if your original algorithm is insecure) by using the old system's decrypt method to decrypt everything, then re-encrypt it all with the new system and storing it again. The application would then just use the new algorithm going forward.

Related

Cookie (un)serialization in Laravel 5.5.42

Security release 5.5.42 "disables all serialization / unserialization of cookie values" - https://laravel-news.com/laravel-5-6-30
But I have my values serialized still, only not unserialized. While I do
Cookie::get('key')
I get something like
"s:5:"value";"
Setting protected static $serialize = true; in App\Http\Middleware\EncryptCookies helps, and so does
unserialize(Cookie::get('key'))
But as I understand unserialize() itself is the source of the problem with this security release, not what I do with the unserialized value later, so this kinda beats the purpose of the update.
Why are my cookies serialized here and how to fix this?
This is actually worth an answer as the question itself is quite interesting.
From a Laravel perspective this isn't a cookie problem as much as it's a APP_KEY config key problem combined with serialize/unserialize.
Relevant quote from the docs:
However, if your application's encryption key is in the hands of a
malicious party, that party could craft cookie values using the
encryption key and exploit vulnerabilities inherent to PHP object
serialization / unserialization, such as calling arbitrary class
methods within your application.
The relevant part is this vulnerabilities inherent to PHP object serialization / unserialization.
Usually the form of explot is Object Injection(the most common at least).
OWASP has a very good example here.
Even php.net has a red warning for it's unserliaze function.
Warning
Do not pass untrusted user input to unserialize()
Cookies come from a user and users are NOT to be trusted.
Since an example is in order I'll just leave the OWASP one here too:
class Example1
{
public $cache_file;
function __construct()
{
// some PHP code...
}
function __destruct()
{
$file = "/var/www/cache/tmp/{$this->cache_file}";
if (file_exists($file)) #unlink($file);
}
}
// some PHP code...
$user_data = unserialize($_GET['data']);
// some PHP code...
In this example an attacker might be able to delete an arbitrary file via a Path Traversal attack, for e.g. requesting the following URL:
http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10:"cache_file";s:15:"../../index.php";}
With that said, I highly recommend reading(even briefly) about serialize/unserliaze vulnerabilities.
If you're using a proper framework, usually, you'll have most security things taken care of IF you don't go out of your way to introduce some vulnerability and you stick to the framework's standards.
It's less efficient but in case of structured data, I replace serialize/unserialize with json_encode/json_decode.

What is the significance of Application key in a Laravel Application?

from laravel docs
Application Key The next thing you should do after installing Laravel
is set your application key to a random string. If you installed
Laravel via Composer or the Laravel installer, this key has already
been set for you by the php artisan key:generate command.
Typically, this string should be 32 characters long. The key can be
set in the .env environment file. If you have not renamed the
.env.example file to .env, you should do that now. If the application
key is not set, your user sessions and other encrypted data will not
be secure!
What I know about application key is: If the application key is not set, generally I do get an exception.
How do this random string help to secure the session?
What are the other uses of this application key?
If I use the same application key everywhere (like staging, production etc..) does it make the application less secure?
what are some best practices for this key
As we can see its used in EncryptionServiceProvider:
public function register()
{
$this->app->singleton('encrypter', function ($app) {
$config = $app->make('config')->get('app');
// If the key starts with "base64:", we will need to decode the key before handing
// it off to the encrypter. Keys may be base-64 encoded for presentation and we
// want to make sure to convert them back to the raw bytes before encrypting.
if (Str::startsWith($key = $this->key($config), 'base64:')) {
$key = base64_decode(substr($key, 7));
}
return new Encrypter($key, $config['cipher']);
});
}
So every component that uses encryption: session, encryption (user scope), csrf token benefit from the app_key.
Rest of the questions can be answered by "how encryption" (AES) works, just open up Encrypter.php, and confirm that Laravel uses AES under the hood and encodes the result to base64.
Further more we can see how its all done by using tinker:
➜ laravel git:(staging) ✗ art tinker
Psy Shell v0.8.17 (PHP 7.1.14 — cli) by Justin Hileman
>>> encrypt('Hello World!')
=> "eyJpdiI6ImgzK08zSDQyMUE1T1NMVThERjQzdEE9PSIsInZhbHVlIjoiYzlZTk1td0JJZGtrS2luMlo0QzdGcVpKdTEzTWsxeFB6ME5pT1NmaGlQaz0iLCJtYWMiOiI3YTAzY2IxZjBiM2IyNDZiYzljZGJjNTczYzA3MGRjN2U3ZmFkMTVmMWRhMjcwMTRlODk5YTg5ZmM2YjBjMGNlIn0="
Note: I used this key: base64:Qc25VgXJ8CEkp790nqF+eEocRk1o7Yp0lM1jWPUuocQ= to encrypt Hello World!
After decoding the result we get (you can try decode your own cookie with session):
{"iv":"h3+O3H421A5OSLU8DF43tA==","value":"c9YNMmwBIdkkKin2Z4C7FqZJu13Mk1xPz0NiOSfhiPk=","mac":"7a03cb1f0b3b246bc9cdbc573c070dc7e7fad15f1da27014e899a89fc6b0c0ce"}
to understand above json (iv, value, mac) you need to understand AES:
https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
Best practices for application key
do store it in .env file only
do not store it in app.php, in fact in any git tracked file
do not change it unless you really want to
invalidate sessions/cookies (user logout)
invalidate password reset tokens
invalidate signed urls
Obvious Note: Changing application key has no effect on hashed passwords since hashing algorithms do not require encryption keys.

PHP password_hash always contains hashkey

I am trying to test the password_hash method for this purpose i have created the following function hashPassword:
function hashPassword($string) {
$settings = array('cost' => 10, 'encryption_key' => 'thisIsMyEncryptionKey1234');
return password_hash($string, PASSWORD_BCRYPT, $settings);
}
Now if i test this with a random string like "test"
The result would be:
$2y$10$thisIsMyEncryptionKeyu5n3NNnKh3DjgJqgb5pE8YOLBclKrVWC
Or if i test it with helloworld:
$2y$10$thisIsMyEncryptionKeyuVw8QRVNw8HbEWHX2oQlArVtne2TzOpS
Can anyone tell me why this is happening? Or is it suppose to be like this?
You should never provide the encryption key manually unless you have a very good reason to do so. I'd recommend reading the docs on password_hash some more.
Proper usage just lets the system figure it all out on its own:
function hashPassword($password)
{
return password_hash($password, PASSWORD_DEFAULT);
}
PHP will then internally choose the best available algorithm and most fitting number of iterations for current hardware, and generate a safe and unique salt.
To validate the password, then use password_verify, and check for required rehashes, for example in a User class:
class User
{
...
public function verifyPassword($password)
{
if(!password_verify($password, $this->hash))
return false;
if(password_needs_rehash($this->hash, PASSWORD_DEFAULT))
$this->setNewHashAndSaveToDB(password_hash($password, PASSWORD_DEFAULT));
return true;
}
}
By using this construct, you ensure hashed passwords are always kept up to date and secure as hardware capacities progress, automatically when a user logs in.
The policy on what algorithm PASSWORD_DEFAULT chooses, and with which config, is as follows:
Updates to supported algorithms by this function (or changes to the
default one) must follow the follwoing rules:
Any new algorithm must be in core for at least 1 full release of PHP prior to becoming default. So if, for example, a new algorithm
is added in 5.5.5, it would not be eligible for default until 5.7
(since
5.6 would be the first full release). But if a different algorithm was added in 5.6.0, it would also be eligible for default at 5.7.0.
The default should only change on a full release (5.6.0, 6.0.0, etc) and not on a revision release. The only exception to this is
in an emergency when a critical security flaw is found in the
current default.
About Encryption key:
Best Encrуption kеy is a binary blob that's gеnеrated from a rеliablе random numbеr gеnеrator. Thе following еxample would bе rеcommеndеd (>= 5.3):
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);
$encryptionKey = openssl_random_pseudo_bytes($key_size, $strong); //$strong will be true if the key is crypto safe
But in your case you just set the string, use some random data for this.

What Kind of Encryption is used by Sentry

I am building an iOS app for an already existing web application I created. The web app uses laravel and sentry to encrypt passwords. New users have to be able to be created from the iOS app.
The server that the web app talks to is written in php but does not use laravel or sentry.
The only sentry function I need is the one they use to encrypt passwords.
What function does sentry use to hash passwords? I am talking about Cartalyst\Sentry\Hashing\NativeHasher
I need to be able to duplicate this function and use it in a separate php file.
i've found this link : https://github.com/cartalyst/sentry/blob/master/src/Cartalyst/Sentry/Hashing/NativeHasher.php
and this code is what you want probably:
public function hash($string)
{
// Usually caused by an old PHP environment, see
// https://github.com/cartalyst/sentry/issues/98#issuecomment-12974603
// and https://github.com/ircmaxell/password_compat/issues/10
if (!function_exists('password_hash')) {
throw new \RuntimeException('The function password_hash() does not exist, your PHP environment is probably incompatible. Try running [vendor/ircmaxell/password-compat/version-test.php] to check compatibility or use an alternative hashing strategy.');
}
if (($hash = password_hash($string, PASSWORD_DEFAULT)) === false) {
throw new \RuntimeException('Error generating hash from string, your PHP environment is probably incompatible. Try running [vendor/ircmaxell/password-compat/version-test.php] to check compatibility or use an alternative hashing strategy.');
}
return $hash;
}

Does PHP use a FIPS-140 compliant RNG to generate session IDs?

A requirement for the deployment of a PHP application I am working on is that is uses FIPS-140 validated cryptographic modules.
The customer has specifically flagged up that "PHP utilizes a cryptographically weak random number generator to produce session ID information" and cited this report: http://berlin.ccc.de/~andreas/php-entropy-advisory.txt
I have advised them on how to set session.entropy_length and session.hash_function to increase entropy, but they have not accepted this, specifically requiring that we use a FIPS-140 compliant RNG.
I'm not certain on the difference between the hash function and the RNG, so am struggling to respond. Can anyone suggest a way of using a FIPS-140 compliant function to generate session ids within php?
We're running PHP 5.4.16 on Windows + SQL Server, in case it matters.
Thanks
A requirement for the deployment of a PHP application I am working on is that is uses FIPS-140 validated cryptographic modules.
My condolences. A headache is to FIPS-140 what a drop of morning dew is to the ocean.
I'm not certain on the difference between the hash function and the RNG, so am struggling to respond. Can anyone suggest a way of using a FIPS-140 compliant function to generate session ids within php?
If you're using ext/mcrypt, mcrypt_create_iv() uses Windows' CryptGenRandom API which should be FIPS-140 compliant. (Or, at minumum, it should be possible to setup that way.) That function is the only good thing about mcrypt, and exists separatef from libmcrypt.
If you're using OpenSSL, and compiled OpenSSL in FIPS mode, you can similarly use openssl_random_pseudo_bytes() and it should use a FIPS-compliant generator.
Finally, if you upgrade to PHP 7+ and use random_bytes(), so long as Windows is FIPS-140 compliant, you're golden.
The hash function really doesn't matter here. You want to use a secure source and that's it. Hashing it doesn't buy you anything. If you're forced to use a hash function, use one of the SHA2 family hash functions (SHA256, SHA384, or SHA512) approved for use in FIPS-140 compliant software.
Session Generator that should pass FIPS-140 audits
<?php
/**
* #return string
*/
function session_id_fips140()
{
if (is_callable('random_bytes')) {
return session_id(bin2hex(random_bytes(32)));
}
if (is_callable('mcrypt_create_iv')) {
return session_id(bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)));
}
if (is_callable('openssl_random_pseudo_bytes')) {
return session_id(bin2hex(openssl_random_pseudo_bytes(32)));
}
// Fail closed. Maybe install random_compat?
throw new Exception("No suitable PRNG is available on the current system!");
}
Usage:
<?php
ini_set('session.
if (!isset($_COOKIE['PHPSESSID'])) {
session_id_fips140();
}
session_start();

Categories