Livewire Strict helps enforce security measures and prevents you from having unprotected sensitive public properties.
Did you know any public Livewire component property is open to manipulation? If not, now you know :)
Let me give you an example. We have a Livewire component that we include in our dashboard:
1<livewire:user-balance :user-id="auth()->id()">
The component itself looks something like this:
1class UserBalance extends Component 2{ 3 public $userId; 4 5 #[Computed] 6 public function balance() 7 { 8 return User::find($this->userId)->balance; 9 }10 11 public function render()12 {13 return view('livewire.user-balance');14 }15}
The $userId
is set as a public property. Now, you might think that because the component is rendered on the back-end inside our Blade file, this component cannot be tampered with. This, however, is not the case. I can use the Livewire
client library to manipulate the $userId
using my browser dev tools and enter:
1Livewire.first().set('userId', 10);
This will grab the first Livewire component on the page and change the $userId
to 10
. Now, I am able to see the balance for this user.
To fix this, you can use the Locked
attribute that is provided by Livewire:
1class UserBalance extends Component2{3 #[Locked]4 public $userId;5 6 // ...7}
You will have to ensure you lock your properties when needed. What if you could instead lock all properties by default and unlock specific properties you want users to be able to modify? This is where the Livewire Strict package comes in. With one line of code, you can lock all properties.
First, install the package:
1composer require wire-elements/livewire-strict
Next, all you have to do is call LivewireStrict::lockProperties()
in the register()
method of your AppServiceProvider
.
1use WireElements\LivewireStrict\LivewireStrict; 2 3class AppServiceProvider extends ServiceProvider 4{ 5 /** 6 * Register any application services. 7 */ 8 public function register(): void 9 {10 LivewireStrict::lockProperties();11 12 // Only enable locally13 LivewireStrict::lockProperties(shouldLockProperties: app()->isLocal());14 }15 16 /**17 * Bootstrap any application services.18 */19 public function boot(): void20 {21 //22 }23}
Now, all properties are locked by default for components that are part of the App\Livewire
namespace. If you want to be more specific you can pass the components
attribute and define specific components and/or namespaces:
1LivewireStrict::lockProperties(components: [MyComponent::class, 'SomeNamespaces/*']);
To "unlock" properties, you can choose to unlock at the component or property level:
1use WireElements\LivewireStrict\Attributes\Unlocked; 2 3class Counter extends Component 4{ 5 #[Unlocked] 6 public $count = 0; 7 8 public function increment() 9 {10 $this->count++;11 }12 13 public function render()14 {15 return view('livewire.counter');16 }17}
In the example above, the public property $count
can now be manipulated without throwing the CannotUpdateLockedPropertyException
exception.
In some cases, you might have a component that contains a lot of public properties, so this would look like the following:
1use WireElements\LivewireStrict\Attributes\Unlocked; 2 3class SignUp extends Component 4{ 5 #[Unlocked] 6 public $firstName; 7 8 #[Unlocked] 9 public $lastName;10 11 #[Unlocked]12 public $email;13}
If you want all public properties to be unlocked, you can add the attribute on the component class level instead:
1use WireElements\LivewireStrict\Attributes\Unlocked; 2 3#[Unlocked] 4class SignUp extends Component 5{ 6 public $firstName; 7 8 public $lastName; 9 10 public $email;11}
That looks a bit cleaner and will have the same result.
So, if you are looking to minimize the chances for your Livewire components to be vulnerable, install the Livewire Strict package.