Como encriptar los IDs en Laravel

Daniel López

Full stack developer

Jun 2020
Jun 19, 2020

Laravel es uno de los frameworks de PHP mas utilizados en la actualidad, y aunque recibe actualizaciones constantemente añadiendo nuevas funcionalidades, hay algunos procesos que aún no incorpora. Uno de ellos es la encriptación automática de ids.

En primer lugar, tenemos que conocer una serie de factores que serán necesario tener claros a la hora de encriptar.

  • APP_KEY: laravel encripta los datos usando una key que se encuentra en el archivo .env. Esta clave se genera automáticamente con la instalación y se puede cambiar usando el comando php artisan key:generate, lo cual es recomendable hacer cada cierto tiempo para hacer más segura nuestra página.
  • Helpers: funciones de ayuda o que realizan funciones específicas.
  • Traits: emula la herencia múltiple en php y se usa cuando se va a usar código en varios lugares de nuestra aplicación.
  • Accesors: da un valor a un atributo del modelo.
  • Appends: añade un nuevo atributo al modelo.
  • Middlewares: filtra las peticiones php

Creación del helper

Desde aquí generamos un código alfanumérico a través de la encriptación de un id numérico. Crearemos el helper en app/Helpers y lo llamaremos Encryptor.php


class Encryptor
{
   public static function method()
   {
       return Config::get('app.cipher');
   }

   public static function hash_key(){
       return hash('sha256', Str::substr(Config::get('app.key'), 7));
   }

   public static function iv()
   {
       $secret_iv = Str::substr(Config::get('app.key'), 7);
       $iv = substr(hash('sha256', $secret_iv), 0, 16);

       return $iv;
   }



   public static function encrypt($value)
   {
       $output = openssl_encrypt($value, self::method(), self::hash_key(), 0, self::iv());
       $output = base64_encode($output);

       return $output;
   }

   public static function decrypt($value)
   {
       $output = openssl_decrypt(base64_decode($value), self::method(), self::hash_key(), 0, self::iv());
       return (int)$output;
   }
}

Las tres primeras funciones se usarán para generar los datos que luego usaremos encriptar el código en las funciones de encrypt y decrypt.

Función method: Recogemos el método de encriptación declarado en el fichero app.php. Por defecto  laravel usa AES-256-CBC

Función hash_key: encriptamos el código del APP_KEY que encontramos en el fichero .env con el método sha256 (se puede usar otro método)

Función iv: generamos el valor que garantiza que el valor encriptado sea único. Aquí podemos usar cualquier valor. Nosotros encriptaremos una parte del APP_KEY y la usaremos como iv.

Funciones encrypt y decrypt: Estas funciones recibirán un valor (el id en este caso) el cual encriptaremos o desencriptaremos usando las funciones php openssl_encrypt/openssl_decrypt y base64_encode/base64_decode respectivamente, usando los valores generados por las funciones anteriores.

Creación del helper

En el trait crearemos el accesor para luego poder hacer un use en cada modelo que necesitemos encriptar un id. Crearemos el helper en app/Trait y lo llamaremos EncryptationId.php

El accesor hará uso de la función encrypt que hemos creado en el helper Encryptor.php


use App\Helpers\Encryptor;

trait EncryptationId
{
 /**
  * Funcion que recupera el id del modelo y lo encripta
  * @param $value valor del id autonumerico
  * @return string con el valor del id encriptado
  */
 public function getEncidAttribute()
 {

   return Encryptor::encrypt($this->attributes['id']);
 }


}

Modelo

Hacemos un use del trait que contiene el accesor y añadimos la variable encid que contendrá el id encriptado al modelo.

use App\Traits\EncryptationId;


class User extends Model
{
   use EncryptationId;
   protected $appends = ['encid'];
}

Controlador

Con hacer uso del modelo para generar un objeto, ya podremos obtener el encid


public function index()
{
    $users = $User::all();

    return view(‘users’, compact(users));
}

public function edit($id)
{
    $user = $User::find($id);
    //dd($user->encid)

    return view(‘user’, compact(user));
}





public function store($id, Request $request)
{
    $user = $User::find($id);
    
    $user->update([
        //$request...
    ])
    return view(‘users’);
}

Vista

En la vista sólo tendremos que hacer uso del objeto que hemos enviado y extraer el encid para usarlo donde queramos.


users.blade.php

@foreach($users as $user)

    Editar usuario: <a href=”/users/{{$user->encid}}”>{{$user->name}} </a>

@endforeach


user.blade.php


<form method="post" action="/user/{{$user->encid}}">
    …..
</form>


Middleware

Añadiremos el código que se encargará de comprobar que lo que está pasando por el middleware contiene la palabra id o _id ya sea enviado por get o por post, y si encuentra ese valor lo desencripta antes de llegar al controlador.


class EncryptMiddleware
{
 /**
  * Handle an incoming request.
  *
  * @param  \Illuminate\Http\Request  $request
  * @param  \Closure  $next
  * @return mixed
  */
 public function handle($request, Closure $next)
 {
   /**
    * Se recoge la request enviada por get y se recorren y desencriptan los parámetros que tiene. El controlador recoge los datos desencriptados para procesarlos correctamente
    */
   foreach($request->route()->parameters as $key => $value){
     if($key == 'id' || Str::endsWith($key, ['_id'])) {
       $request->route()->setParameter($key, Encryptor::decrypt($value));
     }
   }

   /**
* Se comprueba si el método es post. Si lo es se recorren sus parámetros y se comprueba que en los datos enviados por el formulario hay algún parámetro que se llame exactamente ID o que contenga _ID. Si la comprobación es exitosa se desencripta para que el controlador pueda procesar los datos correctamente
    */
   if($request->isMethod('post')){
     $array = [];
     foreach ($request->request as $key => $value) {
       if($key == 'id' || Str::endsWith($key, ['_id'])){
         // Si lo que recibe es un array, se desencripta cada valor del array, se guarda en un array temporal y se aplica sobre el array original de la request
         if (is_array($value)){
           foreach ($value as $key_array=>$array_item) {
             if($array_item != NULL){
               array_push($array, Encryptor::decrypt($array_item));
             }
           }
           $request->request->set($key, $array);
         } else {
           if($value != NULL){
             $request->request->set($key, Encryptor::decrypt($value));
           }
         }

       }
     }
   }

   return $next($request);
 }
}

Web

Todas las rutas que englobe el EncryptMiddleware se verán afectadas por la desencriptación de ids


Route::middleware(‘encrypt)->group(function () {
    Route::get(‘/users’, ‘UserController@index);
    Route::get(‘/users/{id}’, ‘UserController@edit’);
    Route::post(‘/users/{id}’, ‘UserController@store);
}

Y con todo esto ya tendremos la encriptación de ids implementada en nuestra web.

También te puede interesar

La importancia del prototipado: Figma

La importancia del prototipado: Figma

La importancia del prototipado: Figma Durante el proceso del desarrollo de aplicaciones y diseño web, la eficiencia y la efectividad en la fase de concepción de un proyecto son cruciales. Por eso el prototipado no es simplemente una etapa preliminar más, sino que es...

Chat GPT y desarrollo web: ¿acabará con los developers?

Chat GPT y desarrollo web: ¿acabará con los developers?

En la era digital, donde nuestra existencia misma parece colgar del frágil hilo de la última actualización de software, surge una pregunta tan inquietante como el sonido de una notificación no leída: ¿Podrá Chat GPT, con su cerebro electrónico y su encantador ingenio...

Los lenguajes de programación más usados en 2024

Los lenguajes de programación más usados en 2024

A medida que avanzamos en esta década, la tecnología sigue siendo el motor de transformación en todos los sectores, incluyendo cómo interactuamos, consumimos y hacemos negocios en el entorno digital. Para las empresas y profesionales enfocados en la vanguardia...