Introduction
There may be times when your Laravel application's queued jobs, notifications, mailables, or listeners contain sensitive information that you wouldn't want to have exposed. Typically, when storing sensitive information (such as passwords, API keys, etc.) in a database, you'd want to hash or encrypt the data.
Well, you can do the exact same thing with your queued jobs, notifications, mailables, and listeners!
In this article, we're going to quickly look at how to use the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface to encrypt your queued classes for improved security.
Encrypting Laravel Jobs
To understand why we'd want to encrypt your jobs, notifications, mailables, and listeners, let's take a look at a basic example.
We'll imagine our application requires a one-time password (OTP) when signing in. So we generate the OTP and send it to the user (whether this be via an email, SMS, etc.). We may have a job class that looks like so:
1namespace App\Jobs; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldQueue; 5use Illuminate\Foundation\Bus\Dispatchable; 6use Illuminate\Queue\InteractsWithQueue; 7use Illuminate\Queue\SerializesModels; 8 9class SendOneTimePassword implements ShouldQueue10{11 use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;12 13 /**14 * Create a new job instance.15 */16 public function __construct(public readonly string $oneTimePassword)17 {18 //19 }20 21 // ...22}
In the class above, we're not too bothered about how we're sending the OTP. We're more concerned about the argument that's been passed to the job. In this case, the one-time password.
To run the job, we'd do something like so (notice the 123456
that we're passing as the OTP):
1\App\Jobs\SendOneTimePassword::dispatch('123456');
When we dispatch the job, the data is serialized and stored in the queue store (such as the database or Redis). It's held here until the queue worker pulls the job off the queue and processes it.
If you or anyone malicious were to access the queue store, they'd be able to see the following information (beautified for readability) about the pending job:
1{ 2 "uuid": "3d05be68-8cd0-4c3a-8d05-71e86871713a", 3 "displayName": "App\\Jobs\\SendOneTimePassword", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "App\\Jobs\\SendOneTimePassword",13 "command": "O:28:\"App\\Jobs\\SendOneTimePassword\":1:14 {s:15:\"oneTimePassword\";s:6:\"123456\";}"15 }16}
Did you spot it?
The oneTimePassword
property is visible in plain text in the data.command
field! If someone were to access the queue store, they'd be able to see the OTP.
And this could be any other kind of sensitive information that you wouldn't want to be exposed, such as API keys, passwords, social security numbers, etc.
To prevent this, we can update our job class to implement the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface:
1namespace App\Jobs; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldBeEncrypted; 5use Illuminate\Contracts\Queue\ShouldQueue; 6use Illuminate\Foundation\Bus\Dispatchable; 7use Illuminate\Queue\InteractsWithQueue; 8use Illuminate\Queue\SerializesModels; 9 10class SendOneTimePassword implements ShouldQueue, ShouldBeEncrypted11{12 use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;13 14 /**15 * Create a new job instance.16 */17 public function __construct(public readonly string $oneTimePassword)18 {19 //20 }21 22 // ...23}
As a result of using this interface, Laravel will now encrypt the data before storing it in the queue store, and then decrypt it when pulling the job off the queue to process it.
Let's take a look at what the job data might look like now after using the ShouldBeEncrypted
interface:
1{ 2 "uuid": "ea194df6-ebe1-42a6-9e46-b7ece3b61781", 3 "displayName": "App\\Jobs\\SendOneTimePassword", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "App\\Jobs\\SendOneTimePassword",13 "command": "eyJpdiI6IjRpR1FuRG5NTWpMZ28vdytUaGE0Rmc9PSIsInZhbHVlIjoicERX14 MnJieGVleHp3czhYb3drb1N3ZnpHdHd2MVB1OFYvK24xbmlEUHdMcHk4K2Rr15 ekdQMk9uczVFWFBmVkYvc1NneXMwVWVndlBxQkZySThkaTV6bk5NaVAzWnpG16 aTN2MTZkSEVOUElYQzFSMFMxSnl5NzBkL0V1R1JwUDRYVTUiLCJtYWMiOiI017 NTQ4MmU3NmFhMzg1MjZkODcxNDc5YzQyNzE5ZTFlOWQxNzE4OWNlNTE5ODRl18 YmJkN2ZiMjljYzI5Nzc4ODIyIiwidGFnIjoiIn0="19 }20}
The oneTimePassword
property is now encrypted in the data.command
field! This means that even if someone were to access the queue store, they wouldn't be able to see the OTP.
Of course, this is a very basic example, but you can see how powerful this can be when dealing with sensitive information in your queued classes.
Encrypting Laravel Notifications
Not only can you use the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface with jobs, but you can also use it with queued notifications, mailables, and listeners.
This is great as it can add an extra layer of security to them too when they're stored in the queue store.
Let's take an example notification that could be used for sending a one-time password:
1namespace App\Notifications; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldQueue; 5use Illuminate\Notifications\Messages\MailMessage; 6use Illuminate\Notifications\Notification; 7 8class SendOneTimePassword extends Notification implements ShouldQueue 9{10 use Queueable;11 12 /**13 * Create a new notification instance.14 */15 public function __construct(public readonly string $oneTimePassword)16 {17 //18 }19 20 // ...21}
We can dispatch the notification like so (again, notice the 123456
that we're passing as the OTP):
1use App\Notifications\SendOneTimePassword;2 3$user->notify(new SendOneTimePassword('123456'));
If we were to inspect the data stored in the queue store for the pending notification, we'd see the following:
1{ 2 "uuid": "74e8c7d1-151d-4f05-aeae-b4dfcddba1a6", 3 "displayName": "App\\Notifications\\SendOneTimePassword", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Notifications\\SendQueuedNotifications",13 "command": "O:48:\"Illuminate\\Notifications\\SendQueuedNotifications\":3:14 {s:11:\"notifiables\";O:45:\"Illuminate\\Contracts\\Database15 \\ModelIdentifier\":5:{s:5:\"class\";s:15:\"App\\Models\\User\"16 ;s:2:\"id\";a:1:{i:0;i:1;}s:9:\"relations\";a:0:{}s:10:\"17 connection\";s:5:\"mysql\";s:15:\"collectionClass\";N;}s:12:18 \"notification\";O:37:\"App\\Notifications\\SendOneTimePassword19 \":2:{s:15:\"oneTimePassword\";s:6:\"123456\";s:2:\"id\";s:3620 :\"9494b2db-7362-4936-8e31-5179594a1c01\";}s:8:\"channels\";21 a:1:{i:0;s:4:\"mail\";}}"22 }23}
Again, the oneTimePassword
property is visible in plain text in the data.command
field!
However, we can update our notification class to implement the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface:
1namespace App\Notifications; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldBeEncrypted; 5use Illuminate\Contracts\Queue\ShouldQueue; 6use Illuminate\Notifications\Messages\MailMessage; 7use Illuminate\Notifications\Notification; 8 9class SendOneTimePassword extends Notification implements ShouldQueue, ShouldBeEncrypted10{11 // ...12}
This would now result in the pending notification's data being encrypted when stored in the queue store:
1{ 2 "uuid": "6dc8206c-c06c-4f21-a495-659a61546864", 3 "displayName": "App\\Notifications\\SendOneTimePassword", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Notifications\\SendQueuedNotifications",13 "command": "eyJpdiI6InV3V0V0dTM0eXRLa0xWdHpnajBqcEE9PSIsInZhbHVlIjoiTkd5M214 pVZUpSMFVOdlJEa0lDY2d4MzdLdE1URW5rUC9iZERoSGFkVEJ4M3ZMSERlcVhi15 ZmViUEg4S1R6ZlZzQ2dIY0JQV2N0VXczWGs5dGE3Y3JUUkRwN2hVWkNTRlVtTz16 FRQkVnMkVtM0VhWnBRd2U4d05mOS9EVzhuV29JK0pNYkx1cEtIb2hDbm5MbWdH17 aVNrR3VPTjI3em5uMkFKbG00dVNRak5BRGFhRkZqeUtodDU0Q2tCaWNBamR2eU18 1Ec2pDaTBoN0dSbEpRRnROczl5b09CVUlmT2laVDZVZTdxdU9PbGtwQlV1S0lz19 RGRMdTlmVTRWRTZMNnRFbFczZ3NSb25TM0kyYmFyTTIyYmtwY3ZheTJibURhNX20 dXQkV1ZjEwSStGRzFBN1gxQmRYZzRodXc3UEY4a05teCtPVU1sVG0yN3hOd3pB21 TjdyOFluR0gxckdYeHdNZitYYmJMeUxlcm4yRUl5NVB2NHN4WmRrZzJhYVNiRX22 cydzQ3WkM4YTFrZ1dIRnBqLzVndnJOc0U2R1JTUm0vdWVkVVBuUTcvUmcxOWVP23 UER1SjN1VTR1cDQ1eDB1a0l0SWFTMHhQWCtEMkVjcDYzS1AvS042djlHTmo1eU24 11NWdUcGl0dTlkSWVONVIwLzhOZ2M0SDdHQ1k2S0FJUWh4UTJzT3VRR2dESFpK25 MERwZ1dMZUFrRy9aZU55TUdTN3I4SDJjcTQ1M0tjZS9CekZrb3p1OFFucU5YM026 pwTWN1Y1BjTWVCc3E0RDlaSlErSndNRnVZeFFtNExsbzFQSUR6Vmo0WGZSMXJN27 TzNteXgvMEZnRGMxRU9CS1pBZUNEbnV1YVB1b0RZb25ENXQ3WjFuN3RZcHFLZ128 ByamxNa1dlTVV1bmZRWE5hcXd6UXpUZmlzOXc9IiwibWFjIjoiYzgyNjA5MGNk29 NTA3ZmM2MGNiMGQ3MjFjYzQyNTk2MWI0OWZiMGVmMTUyODFjMjYwNDM1YzM1MW30 MyZjY3YmY5YSIsInRhZyI6IiJ9"31 }32}
Encrypting Laravel Mailables
Similar to how we encrypted jobs and notifications, we can also encrypt mailables very easily.
Let's take this example mailable class that could be used for sending a one-time password:
1namespace App\Mail; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldBeEncrypted; 5use Illuminate\Contracts\Queue\ShouldQueue; 6use Illuminate\Mail\Mailable; 7use Illuminate\Mail\Mailables\Content; 8use Illuminate\Mail\Mailables\Envelope; 9use Illuminate\Queue\SerializesModels;10 11class SendOneTimePassword extends Mailable implements ShouldQueue, ShouldBeEncrypted12{13 use Queueable, SerializesModels;14 15 /**16 * Create a new message instance.17 */18 public function __construct(public readonly string $oneTimePassword)19 {20 //21 }22 23 // ...24}
We can send the mailable like so (again, notice the 123456
that we're passing as the OTP):
1use App\Mail\SendOneTimePassword;2use Illuminate\Support\Facades\Mail;3 4Mail::send(new SendOneTimePassword('123456'));
If we were to inspect the data stored in the queue store for the pending mailable, we'd see the following:
1{ 2 "uuid": "07d4671a-b350-4203-9152-d95d10398879", 3 "displayName": "App\\Mail\\EncryptedMail", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Mail\\SendQueuedMailable",13 "command": "O:34:\"Illuminate\\Mail\\SendQueuedMailable\":15:{s:814 :\"mailable\";O:22:\"App\\Mail\\EncryptedMail\":2:{s:15 15:\"oneTimePassword\";s:6:\"123456\";s:6:\"mailer\";16 s:7:\"mailgun\";}s:5:\"tries\";N;s:7:\"timeout\";N;s:17 13:\"maxExceptions\";N;s:17:\"shouldBeEncrypted\";b:0;18 s:10:\"connection\";N;s:5:\"queue\";N;s:15:\"19 chainConnection\";N;s:10:\"chainQueue\";N;s:19:\"20 chainCatchCallbacks\";N;s:5:\"delay\";N;s:11:\"afterCommit\"21 ;N;s:10:\"middleware\";a:0:{}s:7:\"chained\";a:0:{}s:322 :\"job\";N;}"23 }24}
Just like with the jobs and notifications, the oneTimePassword
property is visible in plain text in the data.command
field!
But we can update the mailable class to implement the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface:
1namespace App\Mail; 2 3use Illuminate\Bus\Queueable; 4use Illuminate\Contracts\Queue\ShouldBeEncrypted; 5use Illuminate\Contracts\Queue\ShouldQueue; 6use Illuminate\Mail\Mailable; 7use Illuminate\Mail\Mailables\Content; 8use Illuminate\Mail\Mailables\Envelope; 9use Illuminate\Queue\SerializesModels;10 11class SendOneTimePassword extends Mailable implements ShouldQueue, ShouldBeEncrypted12{13 // ...14}
This would now result in the pending mailable's data being encrypted when stored in the queue store:
1{ 2 "uuid": "e1296554-44b3-4bbb-b5ff-daa6f1660861", 3 "displayName": "App\\Mail\\EncryptedMail", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Mail\\SendQueuedMailable",13 "command": "eyJpdiI6Im1PQUZUWlFmMllYUnNLZmJ2cUxFTlE9PSIsInZhbHVlIjoiUG1SSkJ14 kY1NpdmpsNTVhc0U3dHYzcXFabFUxdkw5blZQSlU4OGw5eHNCNy9DUjlhUFEzZl15 V3UGFTRVpiNitSaGZFUElZN0xITEcwYnQzMFZtSGk0bGFVdW5GcWNBVlh2K0Vja16 FA1dUFmcmVFa1RqNEhDSmthSVJ0c3RweUhlUEJRQTNzUWpmZHhtTVZxVGZSZER317 d1VvZURETFpEb2lPL1VENUhTTjU4eEY2Mk4vemhRL29RTVE4TGVQNklOazAwY1J18 wOFRjMTUydVZZZmd4aWZCY2xQUUNvMmw4bXhhczgvYThCV1dnaENZaURFTWw1OG19 kybEg2cFVYaDZSS3ZRMERKMzJZZDB4M1c0ZXN0bThJNG1oNlNrdVpGeUZmN2crM20 Wl6c09oVkNIN2Y2QVN4dkNXM0hzMGh0N3pDakxpZWpmbjJ2VldHdVdPWWtKcnph21 WGRPUW9POTdQN0syVXNWa0ZUa000SmdrelVFQ1hrUkNrYUV3SXhkcGJGamMwZEV22 XSjRpOWJhZ25FL0NUZ0lpeERWcG9YWjNkT3ozeEJCVG5LTmVoNzB0bkVPeUs0dm23 JxQ2VCRzhsVk42TGF1Y2djYWsxc0ZtQjdPbWtVanF3c3p4cjY5b3d6VTFZRkVPV24 mI1SDlJbGRKeHN6Sy9BOTF1K0UrZnJvNjNja0JXME55ZlBNY1FCWkJ6U3BJbnVE25 YkJzZFdVNFE1aHdCUDNBTzdva3RBdFkzeDA1WExGTlRacys1V01pNTNzOVU4U2R26 ZYUduRHBVSE5lQ3FnSVBQZXVBb2VLSzlKVzVhSkJLaWZKS3gzZm5KUWR3UXRLND27 0iLCJtYWMiOiI1NjEyZjljMmZjNjlmMWI3NmIzYjQxM2MwMmQyNWM0YmIxODg4Z28 jNlNGM5ODAyOTk4YmRiYzYzOGZjNjZhYjU0IiwidGFnIjoiIn0="29 }30}
Encrypting Laravel Listeners
Finally, we can also encrypt listeners using the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface.
Let's imagine we have this event that accepts a one-time password in the constructor:
1namespace App\Events; 2 3use Illuminate\Broadcasting\Channel; 4use Illuminate\Broadcasting\InteractsWithSockets; 5use Illuminate\Broadcasting\PresenceChannel; 6use Illuminate\Broadcasting\PrivateChannel; 7use Illuminate\Contracts\Broadcasting\ShouldBroadcast; 8use Illuminate\Foundation\Events\Dispatchable; 9use Illuminate\Queue\SerializesModels;10 11class MyAwesomeEvent12{13 use Dispatchable, InteractsWithSockets, SerializesModels;14 15 /**16 * Create a new event instance.17 */18 public function __construct(public readonly string $oneTimePassword)19 {20 //21 }22 23 // ...24}
We'll then have a queued listener that listens for the event:
1namespace App\Listeners; 2 3use App\Events\MyAwesomeEvent; 4use Illuminate\Contracts\Queue\ShouldQueue; 5use Illuminate\Queue\InteractsWithQueue; 6 7class QueuedListener implements ShouldQueue 8{ 9 /**10 * Create the event listener.11 */12 public function __construct()13 {14 //15 }16 17 /**18 * Handle the event.19 */20 public function handle(MyAwesomeEvent $event): void21 {22 //23 }24}
It's worth noticing that in this case, it's not actually the listener that directly contains the sensitive data. It's the event that contains the sensitive data.
We can dispatch the event like so (once again, notice the 123456
that we're passing as the OTP):
1use App\Events\MyAwesomeEvent;2use Illuminate\Support\Facades\Event;3 4Event::dispatch(new MyAwesomeEvent('123456'));
Sure enough, if we were to inspect the data stored in the queue store for the pending listener, we'd see the following:
1{ 2 "uuid": "e395f426-1ae5-463b-bf27-6340528dc845", 3 "displayName": "App\\Listeners\\QueuedListener", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Events\\CallQueuedListener",13 "command": "O:36:\"Illuminate\\Events\\CallQueuedListener\":20:{s:5:\"14 class\";s:28:\"App\\Listeners\\QueuedListener\";s:6:\"15 method\";s:6:\"handle\";s:4:\"data\";a:1:{i:0;O:25:\"App\\16 Events\\MyAwesomeEvent\":1:{s:15:\"oneTimePassword\";s:6:\"17 123456\";}}s:5:\"tries\";N;s:13:\"maxExceptions\";N;s:7:\"18 backoff\";N;s:10:\"retryUntil\";N;s:7:\"timeout\";N;s:13:\"19 failOnTimeout\";b:0;s:17:\"shouldBeEncrypted\";b:0;s:3:\"20 job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:15:\"21 chainConnection\";N;s:10:\"chainQueue\";N;s:19:\"22 chainCatchCallbacks\";N;s:5:\"delay\";N;s:11:\"afterCommit23 \";N;s:10:\"middleware\";a:0:{}s:7:\"chained\";a:0:{}}"24 }25}
However, we can update the QueuedListener
class to implement the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface:
1namespace App\Listeners; 2 3use App\Events\MyAwesomeEvent; 4use Illuminate\Contracts\Queue\ShouldBeEncrypted; 5use Illuminate\Contracts\Queue\ShouldQueue; 6use Illuminate\Queue\InteractsWithQueue; 7 8class QueuedListener implements ShouldQueue, ShouldBeEncrypted 9{10 /**11 * Create the event listener.12 */13 public function __construct()14 {15 //16 }17 18 /**19 * Handle the event.20 */21 public function handle(MyAwesomeEvent $event): void22 {23 //24 }25}
As a result, the pending listener's data will now be encrypted when stored in the queue store:
1{ 2 "uuid": "f6e2d019-95b0-4385-9c8d-9004d998388c", 3 "displayName": "App\\Listeners\\QueuedListener", 4 "job": "Illuminate\\Queue\\CallQueuedHandler@call", 5 "maxTries": null, 6 "maxExceptions": null, 7 "failOnTimeout": false, 8 "backoff": null, 9 "timeout": null,10 "retryUntil": null,11 "data": {12 "commandName": "Illuminate\\Events\\CallQueuedListener",13 "command": "eyJpdiI6InJobm5sSTFxdnpueUR3T2k3eHF1NWc9PSIsInZhbHVlIjoiWi9aMGJ14 ub0orNmtZbmVtWEVUT1l6T09XU2NvdUxxb3pSZW5PNFlibnFSTWNteHJtU255bN15 STBXamlFVVl3UzgrRDBxSkw5UzdHbHF2QmdWenJBL3FPZitaQ3FMRURlcnBVbFB16 U4em1tS0NmNWMreUM2R0hTMEwxN0Z2WFEwVnkzQmZjR0NjZ1pOSGt6TzlsRTUOH17 MGRIZlFud0h4RzVFSmliUlBnamhrOCtMUWpFRW5JSlVvdTNnUE1OWGRleGhMENq18 M4Uk0zdjE3SU8xbVRERFBGOE1meUlrSHZramhYSWZXNkdEanNBVFlDcVUy3NkeE19 RGZCcVlDRlFSM09WNlNSdjRZSTJTUHZWdFhUU2thTXpYQUtZa2dPSlQ2SZrS21W20 phZEo1S0h2QmFYRlVhR0wzVldEcmxJYzBqbG5HZFdRc25zU2xmNnNNVSIOHIrQ221 UXFJcDZFZ29LSTcxQThsV0l2S0l3S1RqcGtvRTVtWnZ4VUdwcTNvNjgQUpubjRr22 lmZ3dCbGdjNkpzQTIyZ3A5ZnJmY2tZdU1JU3hQaUVISlM4aXJnNk1xC9HZk1QRE23 Vk1VWGRvL0R0ek1RcURyc1hKZjY2UFZjVExkVm1NSHpSVnFNSGRLchOR1Jyc2Uz24 RzSURGL09sUnZ1ekNMYnQ5b2dUL0dMMGdJU0JkN2MraFhPTlJrR2yMEMrRndOVW25 RTFKZ0RPTFBidWJ6SlhJMnpheVQyanNvOUFEWnlhWk1QN1g1NHheEVhQmd1amVG26 h4SjhhT0FrWnRDNXZIT1dncUdLY1hNMGRydWNyTi9KZjhtdVZEEtxN1BMd2hRMz27 dGFvcE5MUElybngzOGtvZzBqSzZNSncrWnNBbDA0U0h1QkMvdBoUm93Wk9VT0Y328 FZM2Eya0xzaWxTK0hmSlJxa0JQa3RxeTAva2UxSWhYM2FyMmqZDJRNUhCbFFNVG29 d2xMYXJoSiswU0FNcmVQRy9IIiwibWFjIjoiMTg4NjdhZjUY2MxMGIwZGRmNTgy30 lkOTAxNDZjN2EwNWI1MGZjMjIyMmE5ZTNmYzg3NDdlNTg0TVlY2I0MyIsInRhZy31 IiJ9"32 }33}
Should I Encrypt My Laravel Jobs?
Encrypting your queued classes can be a great way to add an extra layer of security to your applications. It can help protect sensitive information from being exposed if someone were to access the queue store.
And the best part is that it's super easy to do (as we've seen above)! All you need to do is implement the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface in your queued classes.
However, it's worth noting that encrypting and decrypting data will add some overhead to your application. Now, I don't actually have any benchmarks to say how big or small this overhead is. It could potentially be so small that it's negligible. On the other hand, it could be something that has a noticeable impact on your application's performance, especially for larger applications.
If I manage to get any benchmarks, I'll be sure to update this article with the results.
But at a bare minimum, I'd recommend encrypting any queued classes that contain sensitive information. This could be things like passwords, API keys, social security numbers, etc.
If you do some experimenting and find that the overhead isn't too much of a performance hit, then you might want to consider encrypting all your queued classes just for consistency. But again, this is something you'd need to test and see how it affects your application. So it's not a one-size-fits-all answer.
Further Reading
If you're interested in finding out about other ways to protect sensitive information that's being passed around your application, you might also want to check out my "Redacting Sensitive Parameters in PHP" article.
It covers how to use PHP's built-in #[\SensitiveParameter]
to redact sensitive information from logs and stack traces.
Conclusion
Hopefully, this article has given a quick insight into how you can use the Illuminate\Contracts\Queue\ShouldBeEncrypted
interface to encrypt your queued Laravel jobs, notifications, mailables, and listeners for improved security.
If you enjoyed reading this post, I'd love to hear about it. Likewise, if you have any feedback to improve the future ones, I'd also love to hear that too.
You might also be interested in checking out my 220+ page ebook "Battle Ready Laravel" which covers similar topics in more depth.
Or, you might want to check out my other 440+ ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.
If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter below.
Keep on building awesome stuff! 🚀