CakePHP 3 Tutorial 20: Obscure URLs

Submitted by naidim on Thu, 10/27/2016 - 09:33

By default CakePHP uses the unique Id of each record to view each record. For example http://hostname/application/model/view/6. This makes things simple and convenient, except when you want to allow an anonymous user to add and view their record, but no one else. Another user could simply iterate the id field and view all records in the table.

Obscurity is not real security, but can be enough in some instances, and is slightly better than no security at all.

Our method is to simply encrypt the ID then encode it for clean URL display.

Is it possible to simply change the encoded and encrypted ID value in the URL to get a record you should not have access to? Absolutely. Is it probable? Yes, if someone wants to go through the trouble of writing a script to millions of possible combinations.

If the information is that important to keep secure then you shouldn't be making it public to ANY anonymous user and should require full unique user identification. This is not for that use case.

1. Encrypt and Encode the Id for View Identification

CakePHP has it's own encrypt/decrypt methods, or you can use PHP's openssl_encrypt/openssl_decrypt, but either way the results should work the same. For our example we'll use openssl_encrypt().

Many of the characters that the encryption will use are not clean for urls. A simple use of base64_encode() function will clean that up.

Add the following to your Controller:

class RecordsController extends AppController
{
    private $password = 'Some32RandomLettersAndNumbers123';
    private $method = 'aes-256-cbc'; // http://php.net/manual/en/function.openssl-get-cipher-methods.php
    private $initializationVector = '16NON-NULLivChar';
    ...
    public function add()
    {
        ...
        if ($this->Records->save($records)) {
                $this->Flash->success(__('The Record has been saved.'));
                $encodedId = base64_encode(openssl_encrypt($records->id, $this->method, $this->password, false, $this->initializationVector));
                return $this->redirect(['action' => 'view', $encodedId]);
    ...

2. Decode and Decrypt the Id to Display the Record

Now in the same controller we need to set our view to decode and decrypt the encoded Id to retrieve the record from the database.

...
    public function view($encodedId = null)
    {
        $id = openssl_decrypt(base64_decode($encodedId), $this->method, $this->password, false, $this->initializationVector);
        $record = $this->Records->get($id);
    ...

And that's all there is to it.

Add new comment