shakespeare-js does not escape #{...} interpolated strings; should it?

74 views
Skip to first unread message

Joey Adams

unread,
Apr 8, 2012, 2:31:44 PM4/8/12
to yeso...@googlegroups.com
I recently created an issue about the surprising (to me) behavior of #{...} interpolation in shakespeare-js (a.k.a. Julius):

    https://github.com/yesodweb/shakespeare/issues/55

See the ticket for more details.  I was asked to move the discussion to the mailing list.  Is this the right place?

One thing I'd like to add, though: if #{x} inserts the literal string x onto the page rather than escaping it, is there any difference at all between shakespeare-js and shakespeare-text?

Greg Weber

unread,
Apr 8, 2012, 8:41:04 PM4/8/12
to yeso...@googlegroups.com
To summarize for everyone, when form fields are submitted they are
xss-sanitized. The main security issue with this is that not every
source of data is submitted through a form.
When a value is interpolated in an html template, the default is to
also html escape it. However, in a javascript (julius) template, there
is no escaping. This is because there is no way for us to know how to
properly escape what we allow, which is arbitrary insertions.

The only way I can think of to solve this is to require all javascript
insertions to be JSON values. We could automatically convert data
types to JSON. This would require making some assumptions that have
potential for confusion. For example, if you inserted a Text, we would
convert that to a JSON string first to avoid any escaping issues. If
you want to insert javascript code, that would have to be a widget.

Personally I would like to see us move in this direction of very
secure by default. We could always provide an escape hatch.

For shakespeare-text there should continue to be no escaping because
we have no idea what it will be used for.

Michael Snoyman

unread,
Apr 9, 2012, 1:55:01 AM4/9/12
to yeso...@googlegroups.com
I have to say, that solution you're recommending is frightening. There
would be no way to generate an ID in your Haskell code and use it in
your Javascript (without jumping through a bunch of hoops).

Here's what it all comes down to: what are people actually using
Julius interpolation for? I don't think it's that commonly used in the
first place, and I definitely don't think people are embedding
user-supplied values in it in general. But that's why I wanted to open
this to the general community: how are you using it?

In my own use cases, whenever I'm embedding user supplied data in JS,
it's going via JSON, and thus all character escaping is being applied
automatically. So for me, this is all a non-issue.

I also think there are better solutions here than just forcing
everything to be JSON, such as forcing the user to explicitly state
the kind of interpolation they want via a sum type. For example:

data JuliusInterpolation = RawText Text | JSON Data.Aeson.Value |
UnsafeText Text

Michael

Greg Weber

unread,
Apr 9, 2012, 8:16:00 AM4/9/12
to yeso...@googlegroups.com
On Sun, Apr 8, 2012 at 10:55 PM, Michael Snoyman <mic...@snoyman.com> wrote:
> I have to say, that solution you're recommending is frightening. There
> would be no way to generate an ID in your Haskell code and use it in
> your Javascript (without jumping through a bunch of hoops).
>
> Here's what it all comes down to: what are people actually using
> Julius interpolation for? I don't think it's that commonly used in the
> first place, and I definitely don't think people are embedding
> user-supplied values in it in general. But that's why I wanted to open
> this to the general community: how are you using it?
>
> In my own use cases, whenever I'm embedding user supplied data in JS,
> it's going via JSON, and thus all character escaping is being applied
> automatically. So for me, this is all a non-issue.
>
> I also think there are better solutions here than just forcing
> everything to be JSON, such as forcing the user to explicitly state
> the kind of interpolation they want via a sum type. For example:
>
> data JuliusInterpolation = RawText Text | JSON Data.Aeson.Value |
> UnsafeText Text

This is what I just proposed. Doesn't seem too frightening :)

Felipe Almeida Lessa

unread,
Apr 9, 2012, 8:49:53 AM4/9/12
to yeso...@googlegroups.com
Speaking about my uses, I currently never call #{} from a
templates/*.julius file. However, I do have a few Widgets that call
functions from these templates. All of these [julius|...|]
interpolations are of form IDs and nothing else. My code would be
perfectly fine with both kinds of interpolations (safe & unsafe).

However, Yesod tries to be secure by default and I don't think that
the interpolation should be unsafe by default. Implementation-wise,
I'd prefer having a

newtype RawJulius = RawJulius Text

and have the default interpolation be of JSON. The drawback is that
the only solution that I see to make this work would be to write
something like

-- This is internal
data JuliusInterpolation = Raw Text | Safe Value

class ToJulius a where
toJulius :: a -> JuliusInterpolation

instance ToJulius RawJulius where
toJulius (RawJulius t) = Raw t

instance JSON a => ToJulius a where
toJulius = Safe . toJSON

which needs (at least) OverlappingInstances and UndecidableInstances.

Cheers,

--
Felipe.

Michael Snoyman

unread,
Apr 10, 2012, 12:15:34 AM4/10/12
to yeso...@googlegroups.com

I think I'd rather force users to explicitly add the toJSON
themselves, and then we could allow a bunch of ToJulius instances. For
examples, all numeric types should be safe candidates for a ToJulius.

Michael

Eric Schug

unread,
Apr 11, 2012, 9:04:40 AM4/11/12
to yeso...@googlegroups.com
Encoding in JSON is not sufficient. In my tests with other web code if
the Javascript is embedded within HTML then it is possible for it to
contain something like {badvalue:"</script><script> insert bad code
here"}. In general I would also replace all "<" and ">" with the string
escape equivalents.

Greg Weber

unread,
Apr 11, 2012, 7:05:40 PM4/11/12
to yeso...@googlegroups.com
So you need JSON + sanitization of the strings in the JSON.
Personally I think insertion of javascript values into HTML should be
done using a templating system. Most client-side templating systems
feature tag stripping.
On the other hand this also wouldn't normally interfere with normal
usage, and I like highly secure by default.

dag.od...@gmail.com

unread,
Apr 12, 2012, 1:32:13 PM4/12/12
to yeso...@googlegroups.com
You might want to try jmacro instead; it is syntactically checked, lexically scoped and handles syntactical interpolation, JSON serialization and HTML sanitation. Julius is as you say, just text interpolation with no knowledge of Javascript at all.

Greg Weber

unread,
Apr 12, 2012, 4:35:24 PM4/12/12
to yeso...@googlegroups.com
The documentation of jmacro didn't explain that that it serializes
into the language that way, although now i see I should have picked up
on that from one of their examples.

This should help guide our approach. However, I think there is
advantage to re-using ToJSON and maintaining our approach of allowing
industry standards of either plain javascript or coffeescript.

The biggest issue with jmacro for a Yesod user is that it doesn't have
build in support for type-safe urls, but there shouldn't be any issue
with using it if you want to.

Reply all
Reply to author
Forward
0 new messages