Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Enable autoescaping in volt, but do not apply to partial(), include() etc

So my app uses quite a lot of partials for things such as the navigation bar, assets, flash messages and more.

For extra safety I'd like to turn on autoescape so that all volt {{ .. }} (PHVOLTTECHO) tags automatically escape input, adding another layer of prevention against XSS issues and more. I'm doing this using setOptions and 'autoescape' => true on the volt engine class.

Turning this on however also auto escapes tags such as {{ partial("partials/navbar") }} which means that the entire navbar turns into plain HTML.

I'm aware that I could use something like <?= $this->partial("partials/navbar") ?> to avoid this, but that kind of ruins the tidyness of everything.

Do you guys have any tips or tricks to overcome this issue?

Perhaps we should add new syntax next to PHVOLTTECHO in the volt compiler, looking like e.g. {! <unsafe string> !}, which passes a boolean to compileEcho function to ignore the escapeHtml line inside that function.



6.4k
{% autoescape false %}
        {% include "partials/your_file" %}
{% endautoescape %}

Would that work for you?



1.6k
edited May '16

Unfortunately not. That would also disable autoescaping of all tags inside your_file.

I just want to disable it for the include/partial functions, but not for anything else.

Also you're including using {% %}, that seems wrong?



48.4k
Accepted
answer

You can try to extend and override functionality in Volt component which will add filters and pass call to a parent method.



6.4k

Yes, mistake on {% include %}, should've been {{ }}.

So, I am still not seeing the problem, why don't you again autoescape whatever you want within the included file?

Or, seems I don't understand you completly.



1.6k
edited May '16

>Yes, mistake on {% include %}, should've been {{ }}. > >So, I am still not seeing the problem, why don't you again autoescape whatever you want within the included file? > >Or, seems I don't understand you completly.

You're right. I can enable and disable autoescape every time I include a partial:

index.volt

{% autoescape false %} {{ partial("partial")

partial.volt

{% autoescape true %} /* partial stuff */

But that means 2 extra lines of code every time I want to include a partial. There's also a security risk that I forget to enable it again.

>You can try to extend and override functionality in Volt component which will add filters and pass call to a parent method.

Good suggestion. I've tried to add an 'unescape' filter usable like {{ partial("..") | unescape })} that disables the autoescape and enables it again as soon as the compileEcho function is called. Unfortunately filters are parsed after compileEcho and not before, so this didn't work.


Thanks for all the suggestions so far though guys.

I think I'll attempt to do a pull request later that adds new syntax similar to {! partial("..") !} which disables the escaper for this one specific echo. I'll have to dive into the C part of phalcon a bit but I'll figure it out.



1.6k
edited May '16

>You can try to extend and override functionality in Volt component which will add filters and pass call to a parent method.

After thinking this through a second time I think I've found a solution using filters which is also really simple. So I'm going to accept your answer.

My syntax to disable escaping now looks like this: {{ partial("partials/assets") | nae }} which looks good enough to me.

I've added the following filter to the volt compiler:

$compiler->addFilter('nae', function ($resolvedArgs, $exprArgs) {
    return $resolvedArgs . ', true';
});

This filter literally hacks a 2nd argument to the code, so the compiled volt with autoescape enabled will look like this:

<?= $this->escaper->escapeHtml($this->partial('partials/assets'), true) ?>

After that I've overwritten the escaper class to use this 2nd argument to ignore the escape action after all:

<?php

namespace Phalcon;

class MyEscaper extends Escaper
{
    public function escapeHtml($text, $ignoreAnyways = false)
    {
        if ($ignoreAnyways) {
            return $text;
        }

        return parent::escapeHtml($text);
    }
}

Now we just have to use our custom class in our DI:

$di->setShared('escaper', new \Phalcon\MyEscaper());

Very nice! The flexibility of this framework continues to amaze me.

Excellent! Good approach!

You see, Phalcon AND PHP are win win!