Encryption/Decryption of Form Fields in Cakephp 3

Encryption/Decryption of Form Fields in CakePHP 3

There's more than one way to solve this (please note that the following code is untested example code! You should get a grasp on the new basics first before using any of this).

A custom database type

One would be a custom database type, which would encrypt when binding the values to the database statement, and decrypt when results are being fetched. That's the option that I would prefer.

Here's simple example, assuming the db columns can hold binary data.

src/Database/Type/CryptedType.php

This should be rather self explantory, encrypt when casting to database, decrypt when casting to PHP.

<?php
namespace App\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use Cake\Utility\Security;

class CryptedType extends Type
{
public function toDatabase($value, Driver $driver)
{
return Security::encrypt($value, Security::getSalt());
}

public function toPHP($value, Driver $driver)
{
if ($value === null) {
return null;
}
return Security::decrypt($value, Security::getSalt());
}
}

src/config/bootstrap.php

Register the custom type.

use Cake\Database\Type;
Type::map('crypted', 'App\Database\Type\CryptedType');

src/Model/Table/PatientsTable.php

Finally map the cryptable columns to the registered type, and that's it, from now on everything's being handled automatically.

// ...

use Cake\Database\Schema\Table as Schema;

class PatientsTable extends Table
{
// ...

protected function _initializeSchema(Schema $table)
{
$table->setColumnType('patient_surname', 'crypted');
$table->setColumnType('patient_first_name', 'crypted');
return $table;
}

// ...
}

See Cookbook > Database Access & ORM > Database Basics > Adding Custom Types

beforeSave and result formatters

A less dry and tighter coupled approach, and basically a port of your 2.x code, would be to use the beforeSave callback/event, and a result formatter. The result formatter could for example be attached in the beforeFind event/callback.

In beforeSave just set/get the values to/from the passed entity instance, you can utilize Entity::has(), Entity::get() and Entity::set(), or even use array access since entities implement ArrayAccess.

The result formatter is basically an after find hook, and you can use it to easily iterate over results, and modify them.

Here's a basic example, which shouldn't need much further explanation:

// ...

use Cake\Event\Event;
use Cake\ORM\Query;

class PatientsTable extends Table
{
// ...

public $encryptedFields = [
'patient_surname',
'patient_first_name'
];

public function beforeSave(Event $event, Entity $entity, \ArrayObject $options)
{
foreach($this->encryptedFields as $fieldName) {
if($entity->has($fieldName)) {
$entity->set(
$fieldName,
Security::encrypt($entity->get($fieldName), Security::getSalt())
);
}
}
return true;
}

public function beforeFind(Event $event, Query $query, \ArrayObject $options, boolean $primary)
{
$query->formatResults(
function ($results) {
/* @var $results \Cake\Datasource\ResultSetInterface|\Cake\Collection\CollectionInterface */
return $results->map(function ($row) {
/* @var $row array|\Cake\DataSource\EntityInterface */

foreach($this->encryptedFields as $fieldName) {
if(isset($row[$fieldName])) {
$row[$fieldName] = Security::decrypt($row[$fieldName], Security::getSalt());
}
}

return $row;
});
}
);
}

// ...
}

To decouple this a little, you could also move this into a behavior so that you can easily share it across multiple models.

See also

  • Cookbook > Database Access & ORM > Database Basics > Adding Custom Types
  • Cookbook > Database Access & ORM > Query Builder > Adding Calculated Fields
  • Cookbook > Tutorials & Examples > Bookmarker Tutorial Part 2 > Persisting the Tag String
  • Cookbook > Database Access & ORM > Behaviors
  • API > \Cake\Datasource\EntityTrait
  • API > \Cake\ORM\Table

How can decrypt Cakephp3 encrypted data right from MySQL?

[Solution] The solution for this particular requirement (we need to encrypt the information at SQL level using a eas so it can be read using another app or directly from MySQL using a query and aes_encrypt / aes_decryp) was to create a custom database type in CakePHP them, instead of using CakePHP encryption method, we implemented PHP Mcrypt.

Now the information is saved to the database from our CakePHP 3 app and the data be read at MySQL/phpMyAdmin level using eas_decrypt and aes_encrypt.

Cakephp 3.5 Security encrypt

If you want to store the data as is, then you need to use a binary type column supported by CakePHP, for MySQL what would be BINARY and BLOB's (when reading such data, CakePHP will give you a data: stream wrapper resource handle).

If you would have to store it in a non-binary column, then you'd need to convert the data accordingly, for example using Base64.

You may also want to look at custom database types that can do the encryption/decryption/conversion transparently.

See also

  • Cookbook > Database Access & ORM > Database Basics > Adding Custom Types
  • Encyption/Decryption of Form Fields in CakePHP 3.

CakePHP 3: Encrypt/decrypt password

Simple answer is: You can't

The whole point of hashing is that you cannot reverse engineer the password. So that when your database is hacked or leaked no harm can be done with the passwords.

Any website showing you your own password has a severe security problem and I would not use it.

There is also no point in showing the encrypted password. Editing a password is not needed, you just overwrite the old one (when they can still provide their old one ofc), and if one of your user forget their own password you should provide them with a recovery system using their email for example.



Related Topics



Leave a reply



Submit