[Lift] Content Security Policy Lift 3

301 views
Skip to first unread message

Peter Petersson

unread,
Jul 29, 2015, 8:45:36 AM7/29/15
to Lift
Hi

I recently recompiled a Lift 3 app against Lift 3.0 snapshot and as the
content security stuff has started to kick in I see a lot of security
messages in both sbt logs and the browser console.
The app has some jquery (v1.11.1) and angular (v1.4.1) and bootstrap
(v3.3.5) scripts/css stuff as well as some own css and js stuff
including angular controller, factories all in its own js/css files.

Although I get allot of ContentSecurityPolicyViolation warnings in sbt
(see below for some snippets) and browse console messages the app still
works in development but *FAILS* when deployed in production (with or
without my experimental security rules settings seen below).

As I do not currently know the best way to approach the security issues
I see I firs tried to "disable" (at least that is what I thought I was
doing) some of the check by experimenting with the security rules and
adding things like the following to Boot.boot

LiftRules.securityRules = () => {
SecurityRules(content = Some(ContentSecurityPolicy(
scriptSources = List(
ContentSourceRestriction.UnsafeEval),
styleSources = List(
ContentSourceRestriction.UnsafeInline,
ContentSourceRestriction.Self))))
}

to see if I could get the app working but I probably have got some
things wrong as it still wont work correctly in production mode.

I can of course do a "rollback" to a milestone (which I have done for
the production deployed version) but I would like to know a bit more
about how this security stuff works so is there any Lift specific
documentation done on this yet? or is it reading code and trying out
stuff at this point? which I obviously have failed to comprehend at this
point ;)

Is there for instance a way to white-list specific resources/resource
paths of similar ?

Below follows some log messages (dev and production mode logs)

Anny help or pointers on how to set up the security rules for my use
case is greatly appreciated.
best regards Peter Petersson

Some log messages in sbt (dev mode)
13:22:04.533 [qtp667921451-1006] WARN
n.l.h.ContentSecurityPolicyViolation - Got a content security violation
report we couldn't interpret:
'Full({"csp-report":{"document-uri":"http://localhost:8080/","referrer":"http://localhost:8080/","violated-directive":"default-src
'self'","effective-directive":"style-src","original-policy":"script-src
'unsafe-eval' 'self'; default-src 'self'; img-src *; report-uri
/lift/content-security-policy-report","blocked-uri":"","source-file":"http://localhost:8080/classpath/fobo/jquery.js","line-number":5571,"column-number":20,"status-code":200}})'.

13:22:08.634 [qtp667921451-1065] WARN net.liftweb.http.LiftRules -
Content security policy violation reported on page
| 'http://localhost:8080/' from referrer 'http://localhost:8080/':
| 'self' was blocked because it violated the
| directive 'default-src http://localhost:8080'. The policy that
specified
| this directive is: 'script-src 'unsafe-eval'
http://localhost:8080; default-src http://localhost:8080; img-src *;
report-uri http://localhost:8080/lift/content-security-policy-report'.

"Production mode" log

==> geronimo.log <==
:
2015-07-29 13:43:08,119 WARN [LiftRules] Content security policy
violation reported on page
| 'http://www.media4u101.se/fobo-angular-lift-roundtrips/' from
referrer '':
|
'http://www.media4u101.se/fobo-angular-lift-roundtrips/classpath/fobo/jquery.js'
was blocked because it violated the
| directive 'script-src 'unsafe-eval''. The policy that specified
| this directive is: 'script-src 'unsafe-eval'; style-src
'unsafe-inline' http://www.media4u101.se; default-src
http://www.media4u101.se; img-src *; report-uri
http://www.media4u101.se/fobo-angular-lift-roundtrips/lift/content-security-policy-report'.

2015-07-29 13:43:08,132 WARN [LiftRules] Content security policy
violation reported on page
| 'http://www.media4u101.se/fobo-angular-lift-roundtrips/' from
referrer '':
|
'http://www.media4u101.se/fobo-angular-lift-roundtrips/classpath/fobo/bootstrap.js'
was blocked because it violated the
| directive 'script-src 'unsafe-eval''. The policy that specified
| this directive is: 'script-src 'unsafe-eval'; style-src
'unsafe-inline' http://www.media4u101.se; default-src
http://www.media4u101.se; img-src *; report-uri
http://www.media4u101.se/fobo-angular-lift-roundtrips/lift/content-security-policy-report'.

2015-07-29 13:43:08,134 WARN [LiftRules] Content security policy
violation reported on page
| 'http://www.media4u101.se/fobo-angular-lift-roundtrips/' from
referrer '':
|
'http://www.media4u101.se/fobo-angular-lift-roundtrips/classpath/fobo/angular.js'
was blocked because it violated the
| directive 'script-src 'unsafe-eval''. The policy that specified
| this directive is: 'script-src 'unsafe-eval'; style-src
'unsafe-inline' http://www.media4u101.se; default-src
http://www.media4u101.se; img-src *; report-uri
http://www.media4u101.se/fobo-angular-lift-roundtrips/lift/content-security-policy-report'.

2015-07-29 13:43:08,101 WARN [LiftRules] Content security policy
violation reported on page
| 'http://www.media4u101.se/fobo-angular-lift-roundtrips/' from
referrer '':
|
'https://www.youtube.com/embed/TRrL5j3MIvo?feature=player_detailpage'
was blocked because it violated the
| directive 'default-src http://www.media4u101.se'. The policy
that specified
| this directive is: 'script-src 'unsafe-eval'; style-src
'unsafe-inline' http://www.media4u101.se; default-src
http://www.media4u101.se; img-src *; report-uri
http://www.media4u101.se/fobo-angular-lift-roundtrips/lift/content-security-policy-report'.







Peter Petersson

unread,
Jul 29, 2015, 11:43:12 AM7/29/15
to Lift
Ok so the related headers in dev is report only, that explains why the
app works in dev mode

X-Content-Security-Policy-Report-Only: script-src 'unsafe-eval'; style-src 'unsafe-inline' 'self'; default-src 'self'; img-src *; report-uri /lift/content-security-policy-report

content-security-policy-report-only: script-src 'unsafe-eval'; style-src 'unsafe-inline' 'self'; default-src 'self'; img-src *; report-uri /lift/content-security-policy-report


whiles it is

content-security-policy: script-src 'unsafe-eval'; style-src 'unsafe-inline' 'self'; default-src 'self'; img-src *; report-uri /fobo-angular-lift-roundtrips/lift/content-security-policy-report

x-content-security-policy: script-src 'unsafe-eval'; style-src 'unsafe-inline' 'self'; default-src 'self'; img-src *; report-uri /fobo-angular-lift-roundtrips/lift/content-security-policy-report

in production

... now I only have to find out what I need to do to make this work
again as scripts are being blocked ;) shouldn't 'self' be sufficient
here ? it's just scripts loaded from sub folders /lift /assets and
/classpath hmmm

Default rule settings as seen in dev (only differs on the style-src bits)

X-Content-Security-Policy-Report-Only: script-src 'unsafe-eval' 'self'; default-src 'self'; img-src *; report-uri /lift/content-security-policy-report

content-security-policy-report-only: script-src 'unsafe-eval' 'self'; default-src 'self'; img-src *; report-uri /lift/content-security-policy-report


Good Lift doc/source here
[1]
https://github.com/lift/framework/blob/master/web/webkit/src/main/scala/net/liftweb/http/SecurityRules.scala

And some general resource on the CSP topic here
[2]
https://docs.google.com/presentation/d/15fx5XLR289_JVG0kQ__WzS1lIU3aNGuZCoQXqLo8sKo/pub?start=false&loop=false&delayms=3000#slide=id.p
[3] https://en.wikipedia.org/wiki/Content_Security_Policy
[4] http://content-security-policy.com/

best regards Peter Petersson

Peter Petersson

unread,
Jul 29, 2015, 12:33:56 PM7/29/15
to Lift
Solved :)
Oki doki I am having a monologue here ;) just wanted to tell you that I
got it working again (sort of), not that complicated when you got your
head around it

The problem was that I had some roundtrip functions generating inline
java script blocks on the page so adding
ContentSourceRestriction.UnsafeInline saved my day (for now).
Now comes the real question is there a way to generate thous roundtrip
scripts into a file instead ? then I could drop the UnsafeInline

best regards Peter Petersson

Antonio Salazar Cardozo

unread,
Jul 29, 2015, 3:07:22 PM7/29/15
to Lift, peterss...@gmail.com, peterss...@gmail.com
Interesting… I thought we were already dealing with that. Can you post
a sample project that shows that issue (the fact that we end up with inline
scripts that aren't being extracted into the page JS file)? Then I can take
a look and see if we can fix that up.

Meantime, you may be able to use a response transformer, take out
`script` elements, and add their contents via S.appendJs, which should
then put it in the page JS. However, it's possible that this would run too
late for the page JS extractor to get it (this happens during the initial
post-processing of the template at the moment).
Thanks,
Antonio

Mariano Lucchetta

unread,
Jul 29, 2015, 6:10:46 PM7/29/15
to Lift, peterss...@gmail.com
I had the same problem then changed to S.appendJs and it works.

Peter Petersson

unread,
Jul 29, 2015, 7:40:52 PM7/29/15
to Mariano Lucchetta, Lift
Thanks, I ended up using S.appendGlobalJs as S.appendJs made the invocation to late.

Antonio Salazar Cardozo

unread,
Jul 29, 2015, 10:51:00 PM7/29/15
to Lift, peterss...@gmail.com, mmluc...@gmail.com, peterss...@gmail.com
Of note: S.appendJs wraps things in a window.onLoad event handler. Probably a good idea
for the future to rename it S.appendJsOnLoad or something else that makes it clear that this
is happening.

Amongst other things, this means that if you use S.appendJs and declare a variable, it won't
be available globally. You'll have to directly assign it to a `window` property instead.

Also Peter—S.appendJs and S.appendGlobalJs return Unit, so you can change this:

  def render() : NodeSeq = {
    val functions = ((for {
      session <- S.session
    } yield 
       <lift:tail>{
       S.appendGlobalJs(JsRaw(s"var myRTFunctions = ${session.buildRoundtrip(getRoundTrips).toJsCmd}").cmd)
       }</lift:tail>
    ) openOr NodeSeq.Empty)
    functions  
  }

To:

  def render() : NodeSeq = {
    S.appendGlobalJs(JsRaw(s"var myRTFunctions = ${session.buildRoundtrip(getRoundTrips).toJsCmd}").cmd)

    NodeSeq.Empty
  }

Thanks,
Antonio
Reply all
Reply to author
Forward
0 new messages