Security Tip: Sensitive Model Attributes

[Tip #8] We need to be careful of sensitive data and where it gets passed around, especially when it relates to models and Javascript.

Security Tip: Sensitive Model Attributes

Traditionally our database models are stored and contained on the server, and we can throw whatever data into them - including sensitive data. However, javascript frameworks like Vue.js, Inertia.js, and even Livewire, make it easy to interact with your models directly in the browser, and if it’s in the browser, it’s publicly visible.

It’s not just javascript frameworks which will do this too! I recently discovered one of my models was leaked on a page in my app because I had passed it into a Blade component, but forgotten to tell Blade it was a prop, not an attribute. So Blade treated it as an attribute and serialized it into the HTML!! It’s super simple to accidently sensitive leak data through models if you’re passing them around the view or javascript layers.

The risk here is simple: if you store sensitive data on your models and send these to the browser, it may end up in the browser, and someone could find it.

💡
As seen recently in the US when Social Security Numbers were exposed in the source code of a government website: https://www.itnews.com.au/news/us-governor-accuses-source-code-viewing-site-visitor-of-hacking-571312

We’re talking about password hashes, dates of birth, API keys, secret messages, staff comments, etc. The list goes on and on… Basically anything that the person making the request shouldn’t have access to.

Lucky for us, Laravel makes it super easy to protect sensitive model attributes.

We can use the $hidden property on our models to specify attributes which should be hidden when the model is turned into an Array or a JSON object:

class User extends Model
{
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = ['password', 'staff_comments'];
}

These attributes will be excluded when the model is turned into an Array or JSON, before being sent to the browser.

Alternatively, we can also use an allow list approach to define the fields we want to be included, blocking all other attributes:

class User extends Model
{
    /**
     * The attributes that should be visible in arrays.
     *
     * @var array
     */
    protected $visible = ['first_name', 'last_name'];
}

Found this security tip helpful? Don't forget to subscribe to receive new Security Tips each week, and upgrade to a premium subscription to receive monthly In Depth articles, or toss a coin in the tip jar.

Reach out if you're looking for a Laravel Security Audit and Penetration Test or a budget-friendly Security Review, and find me on the various socials through Pinkary. Finally, don't forget to check out Practical Laravel Security, my interactive security course.