Encript ID on Url Address

When our web app contain ID in plain number will allow visitor to browse data of other records. Say you have www.example.com/certificates/view.html?id=234. In this case visitor could see record with id of 233, 235, 236 and so on with just change directly in the browser. It will impossible to do the above if we change the with encripted one, such as id=ghfyt== or id= rtyrtrh.

This tutorial will help you to obscure the id in our yii2 web app.

There will be 4 steps:

  1. create encription/decription functions in the componen folder
  2. change main/config
  3. encript the id
  4. decription the encripted id.

In this example I use advanced template. If you use basic template should adjust it.

  1. Create Encription/Decription Functions
    First create new folder in our frontend directory if we do not have it before. After the folder creation your frontend folder will look like:
    frontend
    —assets
    —components
    —config
    —controllers
    —models
    —runtime
    —tests
    —views
    —web

Then create a file in the component folder with any name, in my case I give it GenerikComponent.php and type in the file the following code:

namespace frontend\components;

use yii\helpers\Html;
use yii\base\component;

class GenerikComponent extends Component{

    public function enkrip($id){
        $ciphering = "AES-128-CTR";
        $options = 0; 
        $encryption_iv = '1234567891011121'; 
        $encryption_key = "ANY_KEY_OF_YOUR_CHOICE"; 
        
        $this->encrypted = openssl_encrypt($id, $ciphering, $encryption_key, $options, $encryption_iv);

        return $this->encrypted;
    }

    public function dekrip($id){
        //jenis cipher yg digunakan
        $ciphering = "AES-128-CTR";
        $options = 0; 
        // Non-NULL Initialization Vector for decryption 
        $decryption_iv = '1234567891011121'; 
        $decryption_key = "ANY_KEY_OF_YOUR_CHOICE"; 
    
        $this->decrypted = openssl_decrypt ($id, $ciphering, $decryption_key, $options, $decryption_iv);

        return $this->decrypted;
    }
 
}

I ve created two functions with name enkrip dan dekrip in the file.

  1. Modify main/config.php file

Just amend it with the following code:

'components' => [
       .....
        'generik' => [
            'class' => 'frontend\components\GenerikComponent', 
        ],
        ...
]
        
  1. Encript any ID

Now we can implement our encription function in any part of our app.

a. View,
The simplest one below is my code in index file:

 GridView::widget([
        'dataProvider' => $dataProvider,
        'summary'=>'',
        'filterModel' => $searchModel,
        'columns' => [
            [
                'class' => 'yii\grid\SerialColumn',
                'headerOptions' => ['style' => 'width:3%', 'class' => 'text-left'],
            ],
            ....
            ....
           [
            //  'attribute' => 'certificate_id',
              'label' => 'Certificate#',
              'headerOptions' => ['style' => 'width:5%', 'class' => 'text-center'],
              'contentOptions' => ['style' => 'width:5%', 'class' => 'text-center'],
              'format' => 'raw',
              'value' => function ($model) {                
                $id = Yii::$app->generik->enkrip($model->id);
                return  Html::a($model->id, ['/certificates/view','id'=>$id]);
              },
            ],
            ....
            

We could see in the above $id = Yii::$app->generik->enkrip($model->id) in this code Yii::$app->generik->enkrip() is call function enkrip in the componen generik.

b. Any other place

Of course we could implement our enkrip component in any other place such in controller. We just call it by calling Yii::$app->generik->enkrip(ANY_ID_OR_STRING). And use the dekrip function to see the encripted string into plain string.

If we call the address in the browser will look like example.com/certificates/view.html?id=rfdsu== and when we click it we will get 404 Error Not Found message. It caused by the ID is not known by our action view in the controller. We have to modify it.

  1. Decript actionView Controller.

Go to your controller then modify actionView like this:

    public function actionView($id)
    {
        $id = Yii::$app->generik->dekrip($id);

        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

We just add one line $id = Yii::$app->generik->dekrip($id), it will convert our previous encripted ID into plain ID.

Now you can try again in your browser, should be display our data as usual.

That’s it. Good luck.

I should be noted that it is not impossible but just a bit harder to do so. Normal access checks should still be applied on the action handling the request.

In my opinion a better solution would be to store a UUID (Universally unique identifier - Wikipedia for each record and use that one. No encryption/decryption required especially when dealing with a high amount of models/links at the same time (say you want to list 1000 records and their links) it’s better in terms of performance to already have the number

1 Like

betul gan… :+1: