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

10 claves de UX/UI para diseñar una webapp

10 claves de UX/UI para diseñar una webapp

Cuando se trata de diseñar una webapp, la experiencia del usuario (UX) y la interfaz de usuario (UI) juegan un papel clave. Un buen diseño no solo se trata de estética, sino de cómo los usuarios interactúan con la plataforma y qué tan intuitiva resulta. Aquí te dejo...

Aprende a Desarrollar WebApps

Aprende a Desarrollar WebApps

El desarrollo de aplicaciones web, o webapps, es una de las habilidades más demandadas y valiosas en la era digital actual. Desde pequeñas startups hasta grandes corporaciones, las empresas están buscando maneras innovadoras de conectar con sus usuarios a través de...

El impacto de la 5G en el desarrollo web

El impacto de la 5G en el desarrollo web

La tecnología 5G no es solo una mejora en las telecomunicaciones, sino también un gran cambio para muchas industrias, incluyendo la creación de sitios web. La llegada de la 5G ha revolucionado la manera en que experimentamos y creamos contenido en internet, gracias a...