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
Mysql_Fetch_Assoc(): Supplied Argument Is Not a Valid MySQL Result Resource in PHP
How to Send 500 Internal Server Error Error from a PHP Script
How to Preview an Image Before and After Upload
Generating a Single Entity from Existing Database Using Symfony2 and Doctrine
Redirect After Login on Wordpress
Getting Last Month's Date in PHP
Adding Subscribers to a List Using Mailchimp's API V3
Laravel 5.2 Not Reading Env File
Find First Character That Is Different Between Two Strings
Programmatically Add Product to Cart with Price Change
Request Headers Bag Is Missing Authorization Header in Symfony 2
PHP Regular Expression for Strong Password Validation
Using PHP to Execute Multiple MySQL Queries
MySQL - Access Denied for User