-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Security] Encrypt #686
Comments
@piotrgolasz why was this issue closed? Was it fixed? |
I was going to make changes on a separate branch including changing phpunit tests. |
Ok, so the main point of the change is to drop mcrypt in favour of openssl which is now well-tested and globally maintained software. The second reason for change is to use Encrypt-then-mac encryption, so that before we even try to decrypt anything we can validate the hmac, and therefore we won't accept anything that doesn't come from us. Let me know if you have any suggestions. |
Ok, so I have a test example to prove this. ``
`` I am able to totally change the values of encrypted message, that give valid decryption output. This is because messages are not authenticated (hmaced) The output is: |
Hey @rjd22 what do you think? |
I think security is too important and fast moving for the community team to keep up with going forward, so it's a mistake to just push out a one-off upgrade that we can't guarantee to maintain. We should heavily deprecate Encrypt in the next 3.3 release, and remove it altogether in the next breaking release. There must be decent, active, encryption packages in the composer ecosystem - we could find and recommend some, or leave that for the end user. |
@acoulton I agree. There is no need for Kohana to offer encryption libraries. |
@acoulton @rjd22 I think that having an encryption package is ok, as long as it has the latest security features. To be honest having mcrypt instead of openssl is not something big, however having encryption scheme where ciphertexts are not authenticated is a big security vulnerability, because then random or crafted modification of ciphertext can be decrypted as valid input. So for me this change is not about removing the encryption or changing the underlaying library, but only making sure of ciphertext authenticity by signing ciphertext with hmac using Encrypt-then-hmac scheme. As a reference I can pass the link to laravel's encryption class https://github.com/illuminate/encryption/blob/master/Encrypter.php |
@piotrgolasz
But who can guarantee that? I know what you're suggesting at the moment is quite a simple change, but who will make sure that the next security feature/issue that comes up is noticed and dealt with quickly? Updating the package to whatever the latest security features are now implies that we are planning to keep it up to date in future. That might be our ambition, but I don't see how anyone can honestly claim that's likely to happen. There just aren't enough people actively using or developing Kohana on sites that use encryption. So I think instead of a breaking change to update the latest version of our library which will soon be out of date again, we should make a breaking change to recommend people switch to a package they can rely on. |
Well I would say that making and maintaining a PHP framework surely is not easy, however I think it should have a broad scope of functions so it can be used in wide range of sites. If you would depreciate the encrypt class, then I think you should come up with some way of notifying developers about vulnerability in non-authenticated ciphertexts in past Kohana versions and recommend one or few available alternate libraries. If so, then I think this can be closed. |
I am willing to take this. I am thinking if we could use a second key for the hmac authentication. If that key is empty, not configured, then the class would behave the same way as it currently behaves. This way we can upgrade existing encrypted data. By keeping the old encryption profile with an empty auth key, and adding a new profile with the same encryption key but also with an auth key, the upgrade would be as easy as "decrypt with old profile then encrypt with the new one". Let me know what you guys think. |
+1 Also proper padding would be in need (such as one described here http://stackoverflow.com/questions/7314901/how-to-add-remove-pkcs7-padding-from-an-aes-encrypted-string) |
Thanks @piotrgolasz. Adding proper padding scheme would make keeping BC even harder. For that, we might need another config setting, and the code should pad the text if it is set to Not sure if I want to keep BC anymore. I guess a cleaner class + an example minion task in the docs would be much better. |
I think changing the config to:
From one side you don't want to make breaking changes, from the other side you don't want to have insecure default settings. |
I still think we should just remove Encrypt altogether. However if you're keen to keep (and maintain) it then the proposal looks reasonable. |
In that case what should we do with |
Maybe require https://github.com/defuse/php-encryption and write a wrapper that uses Kohana config? |
Ark. I forgot about That would give us the flexibility to provide a roughly-compatible interface without being responsible for maintaining the security implementation itself. |
* Edited to replace with the correct benchmark screenshot. I want to share with you some of my findings as I played with the The library is simple, straight-forward to use and looks serious and promising. The main Crypto class that we need has 2 types of methods to encrypt:
I was first exploring the implementation with the user provided password, however it turned out the decryption process is (intentionally) very slow. It might not be adequate to use for sessions (that need to be encrypted/decrypted with every request). In order for me to have an objective view of the difference between the two methods, I used PhpBench to benchmark: Encryption Class used for benchmarkingnamespace enov\BenchDefuse;
use Defuse\Crypto\Crypto as Crypto;
use Defuse\Crypto\Key as Key;
class Defuse
{
protected $key;
public function __construct()
{
$key = Key::createNewRandomKey();
}
public function encrypt_decrypt_pwd()
{
$password = 'Any password works here, even short ones';
$text = 'This is the secret message';
$ciphertext = Crypto::encryptWithPassword($text, $password);
$plaintext = Crypto::decryptWithPassword($ciphertext, $password);
}
public function encrypt_decrypt_key()
{
$key = Key::createNewRandomKey();
$text = 'This is the secret message';
$ciphertext = Crypto::encrypt($text, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);
}
public function noop()
{
// do nothing
}
public function zleep()
{
usleep(100);
}
} PhpBench Benchmark class<?php
use enov\BenchDefuse\Defuse;
class DefuseBench
{
/**
* @Revs(10)
*/
public function benchEncryptDecryptPwd()
{
$defuse = new Defuse();
$defuse->encrypt_decrypt_pwd();
}
/**
* @Revs(10)
*/
public function benchEncryptDecryptKey()
{
$defuse = new Defuse();
$defuse->encrypt_decrypt_key();
}
/**
* @Revs(1000)
*/
public function benchNoop()
{
$defuse = new Defuse();
$defuse->noop();
}
/**
* @Revs(1000)
*/
public function benchZleep()
{
$defuse = new Defuse();
$defuse->zleep();
}
} ResultNote that each decryption takes more than half a second on average on my laptop. Now using the second method requires the developer to generate a random key via the library and save it (most probably in config). So I wonder if that would result in too much support request afterwards, about how to use and upgrade. Another thing that I was thinking, what if we remove the encryption feature completely from Waiting for your comments. Thanks! |
Why don't you use native openssl methods, like laravel does: https://github.com/illuminate/encryption/blob/master/Encrypter.php Or phpseclib for that matter? |
Because Laravel does not follow best practices. OpenSSL is not the On Thu, Aug 4, 2016, 07:41 Piotr G. [email protected] wrote:
|
@shadowhand can you elaborate on that or PM me with the answer @ [email protected] |
@piotrgolasz @paragonie lays it all out in https://paragonie.com/white-paper/2015-secure-php-data-encryption tl;dr: MCrypt is out. Defuse/libsodium is best. OpenSSL is fine, if you have nothing else. |
@shadowhand Any difference between defuse and phpseclib? |
@enov thanks for the work on this. I think ideally we should keep support for encrypted sessions (using an external driver) but it does seem like password-based encryption will be too slow. We could provide a minion task (or even just a small standalone script, since presumably Defuse just needs the composer autoloader) to generate a key if required, if that would help? So long as we throw a sensible and helpful exception if key is empty / not configured then I think we should be able to point users in the right direction. They'll already have had to manually require defuse as well, so it's not unreasonable to expect them to configure it once installed. |
Beside travis failing it looks good. |
Thanks @piotrgolasz for the review. |
@enov when do you think this can be solved? |
http://php.net/manual/de/function.mcrypt-get-key-size.php this function is deprecated. Is here a valid php 7.1 solution without warnings? :) |
@Daijobou the right solution is to stop using the Encrypt class. It's bad and probably not secure. |
Correct, but not only I use Encrypt, kohana too. See https://github.com/kohana/core/blob/3.3/master/classes/Kohana/Session.php#L146 or https://github.com/kohana/core/blob/3.3/master/classes/Kohana/Session.php#L305 UPDATE: I found a working solution with koseven (kohana for php7) project and openssl as encrypt type. |
Very easy to stop using Session class too. |
According to: https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong mcrypt is no longer a secure encryption mechanism.
Therefore I would suggest swapping from mcrypt to openssl, which is now considered a Core Internet Infastructure.
I would therefore suggest applying this patch: https://github.com/piotrgolasz/core/commit/b6769b4a1c49ac554ef7ffcfde48e715b22eedfb
This uses openssl in two modes: aes-128-cbc and aes-256-cbc, using the Encrypt-then-MAC scheme. It also allows using RSA encryption using Encrypt-then-Sign scheme. This exact method is used in Laravel framework.
Before, the encryption was not hmac-ed, meaning that crypto originating from it could be susceptible to padding oracle attacks. With this patch, first the check hash($ciphertext,$key,$hash) == $hmac is made, so that if the hashes don't match, we already know that this message is not valid, and therefore we don't have to decrypt.
The text was updated successfully, but these errors were encountered: