plone/mockup

Mockup requires `unsafe-eval` for `script-src` rule when configuring CSP header

Opened this issue · 10 comments

This can be reproduced as follows:

  1. Create a docker-compose.yml with this contents:
version: '2'

services:
  nginx:
    container_name: nginx
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ${PWD}/nginx.conf:/etc/nginx/conf.d/default.conf
    network_mode: "host"
  1. Next to it, create a nginx.conf with this:
server {
    listen 80;
    server_name test_csp.plone.com;

    add_header Content-Security-Policy "script-src 'self';";

    location / {
        limit_except GET POST { deny  all; }
        rewrite ^(.*)$ /VirtualHostBase/http/test_csp.plone.com:80/Plone/VirtualHostRoot$1 break;
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Authorization "";
    }

}
  1. Edit your /etc/hosts and configure test_csp.plone.com to point at 127.0.0.1
  2. Start a fresh Plone listening in 8080 and create an empty Classic Plone site
  3. Where you put the docker-compose.yml and nginx.conf run docker compose up

At this point, you should be able to open your browser and point to http://test_csp.plone.com/ to reach your site. If you try to login by opening the login modal, you will not be able to, and you can see an error message in the developer tools

Uncaught EvalError: call to Function() blocked by CSP
   dr Underscore
   render modal.js:427
   render modal.js:901
   _show modal.js:971
   ajaxXHR modal.js:616
   jQuery 6
   createAjaxModal modal.js:608
   show modal.js:908
   init modal.js:592
   jQuery 8
   init modal.js:589
   d base.js:59
   n base.js:105
   c base.js:40
   initPattern registry.js:119
   scan registry.js:200
   init registry.js:71
   jQuery 9
   init registry.js:64
   17704 patterns.js:74
   Webpack 5
template.js:87:13
   dr Underscore
   render modal.js:427
   render modal.js:901
   _show modal.js:971
   ajaxXHR modal.js:616
   jQuery 6
   createAjaxModal modal.js:608
   show modal.js:908
   init modal.js:592
   jQuery 8
   init modal.js:589
   d base.js:59
   n base.js:105
   c base.js:40
   initPattern registry.js:119
   scan registry.js:200
   init registry.js:71
   jQuery 9
   init registry.js:64
   17704 patterns.js:74
   Webpack 5

Now, if you edit the nginx.conf and change the line

    add_header Content-Security-Policy "script-src 'self';";

To this

    add_header Content-Security-Policy "script-src 'self' 'unsafe-eval';";

Then kill nginx and run docker compose up , you can now see the login modal and everything works fine.

This issue is related to jashkenas/underscore#906 and jashkenas/underscore#2273 (Which basically are the same issue).

I don't know if this can be exploited in any way, however it is an issue, being that unsafe-eval completely blocks the usage of _.template.
On the second issue, an alternative is proposed (https://github.com/silvermine/undertemplate), would moving to this be acceptable?

thet commented

I had a similar problem directly in Patternslib:
Patternslib/Patterns@989fa9f
Patternslib/Patterns@e38f987
Patternslib/Patterns@78c544b

That's interesting, that underscore has the same problem.

It's necessary to fix this problem.

I didn't know about https://github.com/silvermine/undertemplate but I think it's fine to use it to get rid of the CSP error and move forward.

Sorry, I never had this one. But undertemplate looks good as we might get rid of underscore completely then, because it's mainly used for templates since ES6 rewriting.

@thet Well, I started replacing _.template with this undertemplate, however I found that there are templates that in fact do have some JS evaluation (for instance https://github.com/plone/mockup/blob/master/src/pat/relateditems/templates/toolbar.xml) so this cannot be simply replaced, sounds like I will need to refactor them... unless you have a better idea?

While migrating pat-select2 (unfinished #1295 🫣) we talked about replacing relateditems with a new pattern not using select2 anymore. @MrTango had an insteresting approach which we maybe should look more into it instead of fiddling around with the current implementation. but that's of course a larger task than simply refactor a template to undertemplate.

thet commented

@frapell looks like undertemplate does not support conditional statements like <% if ....
That looks like a showstopper for undertemplate to me.
In that case another templating library would probably be better.

There is ejs, which looks similar in syntax, but I think it has the same CSP problem: https://github.com/mde/ejs
or moustache instead?

@thet Right, the problem is with evaluating JS code within the template, which you cannot do in undertemplate nor moustache, and yeah, ejs seems to have the same issue mde/ejs#468

I don't really see other way around than using a templating lib that doesn't allow JS evaluation, and do all our logic in code, and not the templates. That does remove flexibility into being able to change the template used for rendering the widget, but then again, is anyone really doing it?

@petschki Didn't know you were working on that, it could be a good opportunity to strip out _.template usage...

But that's all obsolete when we come up with a new relateditems solution, which I'm really lookging forward to!