Explicamos cómo cifrar y descifrar valores con AES-256-CBC utilizando la fachada Crypt de Laravel. Cubrimos desde la generación de APP_KEY y los model casts hasta el almacenamiento seguro de datos personales.
El servicio de cifrado de Laravel ofrece una interfaz sencilla para cifrar y descifrar valores usando el cifrado AES-256-CBC (o AES-128-CBC) de OpenSSL.Todos los valores cifrados por Laravel se firman con un código de autenticación de mensaje (MAC).
Con esto, si el valor cifrado se altera, ya no se puede descifrar.
Antes de usar el cifrado, la clave key en config/app.php debe estar configurada.
Este valor se lee de la variable de entorno APP_KEY.Genera una clave segura con el comando php artisan key:generate.
Usa el generador de números aleatorios seguros de PHP para producir una clave criptográficamente segura.
php artisan key:generate
Suele generarse automáticamente al instalar Laravel. La clave generada se guarda en el archivo .env.
Cambiar la clave de cifrado hace que se desconecten todas las sesiones de usuario autenticadas.
Es porque Laravel cifra todas las cookies, incluidas las de sesión.Además, los datos cifrados con la clave anterior no podrán descifrarse.Para mitigar este problema, puedes listar claves antiguas separadas por comas en APP_PREVIOUS_KEYS.
Para cifrar, Laravel siempre usa la clave actual; para descifrar, si falla con la clave actual, prueba las claves antiguas en orden.
Así los usuarios pueden seguir usando la aplicación durante la rotación de claves.
Descifra un valor con decryptString de la fachada Crypt.
Si no se puede descifrar correctamente (por ejemplo, MAC no válido), se lanza una DecryptException.
use Illuminate\Contracts\Encryption\DecryptException;use Illuminate\Support\Facades\Crypt;try { $decrypted = Crypt::decryptString($encryptedValue);} catch (DecryptException $e) { // Manejo del fallo de descifrado abort(400, 'Datos no válidos.');}
Usando el cast encrypted en un modelo Eloquent, el cifrado y descifrado del atributo son automáticos.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;class User extends Model{ protected function casts(): array { return [ 'secret_note' => 'encrypted', // Cifrado de string 'profile_data' => 'encrypted:array', // Cifra un array 'preferences' => 'encrypted:collection',// Cifra una colección 'metadata' => 'encrypted:object', // Cifra un objeto 'settings' => 'encrypted:json', // Cifra como JSON ]; }}
Con el cast configurado, la asignación y la lectura del atributo cifran y descifran automáticamente.
// Se cifra automáticamente al guardarse en la BD$user->secret_note = 'Nota secreta';$user->save();// Se descifra automáticamente al leerecho $user->secret_note; // 'Nota secreta'
Los casts encrypted:* usan internamente Crypt::encrypt y Crypt::decrypt.
Se recomienda usar el tipo de columna text o longText en la base de datos.
Schema::create('profiles', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); $table->text('my_number')->nullable(); // El valor cifrado se guarda como text $table->text('bank_account')->nullable(); $table->timestamps();});