Skip to content
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

Upgrade path after security overhaul #4461

Closed
basil-inc opened this issue Jul 26, 2014 · 6 comments
Closed

Upgrade path after security overhaul #4461

basil-inc opened this issue Jul 26, 2014 · 6 comments
Assignees
Milestone

Comments

@basil-inc
Copy link
Contributor

By upgrading to the last dev-master version, the #4458 commit by @samdark broke my code.

I understand that security gets beefed up, and I'd like to upgrade my code to the latest standards, but this means that I need to re-encrypt my existing encrypted columns in the database to the new standard. The upgrade guide contains settings to emulate the legacy encryption which used to work up till now, but have apparently been removed:

return [
    'components' => [
        'security' => [
            'cryptBlockSize' => 16,
            'cryptKeySize' => 24,
            'derivationIterations' => 1000,
            'deriveKeyStrategy' => 'hmac', // for PHP version < 5.5.0
            //'deriveKeyStrategy' => 'pbkdf2', // for PHP version >= 5.5.0
            'useDeriveKeyUniqueSalt' => false,
        ],
        // ...
    ],
    // ...
];

What would be the best way to do this transition? I would need to write a migration using both the "old-style" security for decryption and the "new style" security for encryption.

@samdark
Copy link
Member

samdark commented Jul 26, 2014

Checkout SecurityHelper from previous commits and use it to decrypt data.

@samdark
Copy link
Member

samdark commented Jul 26, 2014

I'll mention it in upgrade guide.

@samdark samdark added this to the 2.0 RC milestone Jul 26, 2014
@samdark samdark self-assigned this Jul 26, 2014
@basil-inc
Copy link
Contributor Author

I wrote a migration to convert my encrypted columns. I'm sharing it here for those who face the same problem.

It requires that you include the old Security helper class, as @samdark suggested. You only need to enter your encryption keys and fill in an array with the names of the tables and their encrypted columns; the code assumes there's also a primary key column in every table called id.

If the process is interrupted, it is safe to run the migration again. Values will only be re-encrypted if both the decryption and encryption lead to a string of more than 0 characters. In my database, empty strings are not encrypted but stored as NULL values in the db; this might be different in your case so change the code accordingly.

<?php
use yii\db\Migration;
use yii\db\Query;
use yii\helpers\Security; // temporarily added to the yii\helpers folder
use yii\helpers\Console;

class m140726_144401_securityOverhaul extends Migration
{
    public function up()
    {
        $connection = \Yii::$app->db;
        /**
         * fill this array with the names of tables and columns
         * which include encrypted data.
         * The code assumes there's also a column called id
         */
        $tables = [
            'Table_1' => [
                'encrypted_column_1',
                'encrypted_column_2',
                'encrypted_column_3',
            ],
            'Table_2' => [
                'encrypted_column_1',
                'encrypted_column_2',
                'encrypted_column_3',
            ],
            'Table_3' => [
                'encrypted_column_1',
                'encrypted_column_2',
                'encrypted_column_3',
            ],
        ];

        foreach ($tables as $tablename => $columns) {

            Console::output('=======================');
            Console::output('Converting table ' . $tablename);

            $count = (new Query())->from($tablename)->count();

            $rowcount = 0;
            Console::startProgress($rowcount, $count);

            $query = (new Query())
                ->select('id')
                ->addSelect($columns)
                ->from($tablename)
                ->orderBy('id ASC');
            foreach ($query->each() as $row) {
                $rowcount++;
                $changes = [];
                foreach ($columns as $columnname) {
                    if (strlen($row[$columnname]) > 0) {
                        $cleartext = Security::decrypt($row[$columnname], 'YOUR_OLD_ENCRYPTION_KEY');
                        if (strlen($cleartext) > 0) {
                            $changes[$columnname] = Yii::$app->getSecurity()->encryptByKey($cleartext, 'YOUR_NEW_ENCRYPTION_KEY');
                        }
                    }
                }
                if (count($changes) > 0) {
                    $connection->createCommand()->update($tablename, $changes, 'id = :id', [':id' => $row['id']])->execute();
                }
                Console::updateProgress($rowcount, $count, str_pad($row['id'], 6));
            }
            Console::endProgress();

        }
    }

    public function down()
    {
        echo "m140726_144401_securityOverhaul cannot be reverted.\n";

        return false;
    }
}

@Borales
Copy link
Contributor

Borales commented Jul 28, 2014

@samdark you forgot to remove unnecessary $deriveKeyStrategy from PHPDoc blocks - it is confusing..

@samdark
Copy link
Member

samdark commented Jul 28, 2014

@Borales be24a2e

@tom--
Copy link
Contributor

tom-- commented Jul 28, 2014

A more general version of this problem is migration of data from Yii1 apps. For that it seems you can follow Using Yii1 with Yii2 in the Guide to get access to both crypto APIs at the same time.

With that you have several options, best of which is to change the Yii1 app to use Yii::$app->security instead of Yii::app()->security and use a migration like the one @docsolver shows above.

Might want to say something about this in the Upgrading page of the Guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants