Overriding e() (or any of the Laravel Helpers)

Published 5 months ago by devonblzx

So, prior to 5.5, you could require a file at the top of bootstrap/autoload.php.

Now, I can't seem to find a way to override Laravel helper functions reliably:

  1. https://github.com/funkjedi/composer-include-files doesn't seem to work any longer.
  2. Composer autoloaded files load after the Laravel Helpers.
  3. Adding in public/index.php does not override Helpers for testing / console.

Does anyone have a reliable solution?

The Laravel escape function is lacking when it comes to protecting against Vue.js interpolation injections, so I'd like to implement my own solution to replace curly braces.

A temporary solution I've used is to set the Blade echo format to my own function that incorporates:

preg_replace('/({|}|{|}|{|})(?=\S)/', '$1 ', $value);

However, this is not full coverage since the echo format is not used everywhere.

Updated with regex solution

bashy
bashy
5 months ago (1,002,700 XP)

Is this to do with double encoding?

click
click
5 months ago (79,510 XP)

@bashy no this is related to the vue interpolation issue mentioned here: https://laracasts.com/discuss/channels/vue/vue-interpolation and here https://laracasts.com/discuss/channels/laravel/laravel-security-issue-1?page=3#reply-419603

I doubt if you can overwrite the e() function. There is no facade being called inside the e() that you can configure. And adding your own helper files which defines it's own e() method does not work because the helper of laravel is loaded earlier than my custom helper file...

However, this is not full coverage since the echo format is not used everywhere.

Is this a problem? The thing you are trying to solve is only related to showing the blade files or not?

As a reference a working example that strips out all {{ and }} occurrences from the content of $variable when you use {{ $variable }} in your blade files. note as mentioned in the comment below this will break json strings.

// add this line to AppServiceProvider::boot()
\Blade::setEchoFormat('e(str_replace(["{{","}}"],"",%s), true)');

I doubt if this is a good idea. Better would be to just solve the vuejs interpolation issue. A solution is given in this topic by nashy: https://laracasts.com/discuss/channels/vue/vue-interpolation

devonblzx

@m-rk Correct.

Further testing shows that replacing }} breaks some JSON encoded in the app I'm working on.

I think this will work:

str_replace(['{{', '}}'], ['{ {', '} }'], $value);

As this will allow JSON where we want it but still prevent Vue from evaluating the template.

Still looking for a way to override e() but I'll use Blade echo format for now.

click
click
5 months ago (79,510 XP)

@devonblzx yes of course, json will be broken if you start removing or replacing those curly braces.

Also take a look at this comment that gives a solution for the interpolation issue by setting the delimiters of vue to something that never matches: https://github.com/vuejs/vue/issues/4223#issuecomment-294864675

your components should still work after this but it won't parse the curly braces in your source code.

bashy
bashy
5 months ago (1,002,700 XP)

I see. Do you do a lot of user input rendered on the page by the server then?

devonblzx

Is this a problem? The thing you are trying to solve is only related to showing the blade >files or not?

As a reference a working example that strips out all {{ and }} occurrences from the >content of $variable when you use {{ $variable }} in your blade files.

It's a problem because it doesn't work if we call double encoding. Enabling Blade::doubleEncode() overwrites the echo format. There are a few other caveats and areas that echo format doesn't have complete coverage.

The short term fix being we remove Blade::doubleEncode() and actually set the second argument of e() to true when we define our echo format.

It's not a major concern yet, but it is surprising there seems to be no way to overwrite helper functions now.

devonblzx

I see. Do you do a lot of user input rendered on the page by the server then?

For this application, yes. There is a lot of server side rendering and Vue has a wide scope with #app. Relying on v-pre would not be optimal.

bashy
bashy
5 months ago (1,002,700 XP)

But rendering from query strings? Everything database will be escaped and fine. I've tested it a lot and I can't exploit this.

devonblzx

But rendering from query strings? Everything database will be escaped and fine. I've tested it a lot and I can't exploit this.

@bashy

Laravel does encode quotes which makes it hard to really exploit this, but I still want the extra assurance. Saving a user name as a simple function call does work. However, taking advantage of this without quotes would certainly be a challenge.

click
click
5 months ago (79,510 XP)

As an example add this

{{ constructor.constructor("alert('xss')")() }}

to one of your database records that will be printed in your blade files with the regular blade echo brackets: {{ $article->title }}

bashy
bashy
5 months ago (1,002,700 XP)

Well. I've broken my profile now on here :D

click
click
5 months ago (79,510 XP)

@bashy haha nice. I suppose on many websites it is this easy to break the site. I saw that laracasts uses on most places (like in the forum) already v-pre. But apparently they forgot it on one spot

my profile now has a nice alert box

@JeffreyWay FYI

<p class="is-bold in-caps">
{{ auth()->user() }} at
a UK Company
</p>
bashy
bashy
5 months ago (1,002,700 XP)

Yeah didn't render server-side though which is good :)

click
click
5 months ago (79,510 XP)

No that was also not what I was expecting. And the cookies are set to http only so hijacking user sessions is not possible as far as I know.

But I can imagine this is possible for many websites that are using vue

bashy
bashy
5 months ago (1,002,700 XP)

Yeah it's not. Loads of other things you can do though. Maybe phishing attack or something if people don't realise.

Please sign in or create an account to participate in this conversation.