Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KaTeX auto-render appears to be incompatible with strict Content-Security-Policy settings #1968

Closed
VorpalBlade opened this issue May 5, 2019 · 4 comments
Labels

Comments

@VorpalBlade
Copy link

KaTeX auto-render appears to be incompatible with strict Content-Security-Policy settings.

Because of the onload handler for auto-render.min.js, 'unsafe-inline' is required in the Content-Security-Policy header sent by the server (instead of just 'self' for self-hosted KaTeX and, if using a CDN, said CDN).

To Reproduce:
Steps to reproduce the behavior:

  1. Set up a server with a strict Content-Security-Policy that allows loading the javascript files for KaTeX but not unsafe-inline.
  2. Use auto-render plugin.
  3. Observe it not working & error in browser console.

Expected behavior:
One of the following:

  • Unsafe-inline should not be needed.
  • It should be documented that unsafe-inline is required for auto-render.

I tried to get it working using the described here, but that doesn't seem to work for onload, or I did something wrong. That could be another option to document (if it is possible to get it to work). Though this stackoverflow post seems to suggest that won't work? (I'm not a JS guru.)

Environment (please complete the following information):

  • KaTeX Version: 0.10.1
  • Device: Desktop
  • OS: Ubuntu 18.04
  • Browser: Chromium and Firefox both tested
  • Version: Chromium 73.0.3683.86 & Firefox 66.0.3
@VorpalBlade VorpalBlade added the bug label May 5, 2019
@kevinbarabash
Copy link
Member

kevinbarabash commented Jul 7, 2019

This is a server configuration issue not a KaTeX issue. Since the server is configured without unsafe-inline it shouldn't allow any javascript files loaded from a CDN to run. I had a look at the MDN page you linked to and nonce seems like it might do the trick but I've never used it before.

@Jieiku
Copy link

Jieiku commented Jun 8, 2022

I actually had a heck of a time getting this setup in a way that did not cause a security violation with strict CSP. (part of the problem is that the firefox developer console does not highlight specifically the issue, it simply states there was a violation.)

For anyone that finds this issue, I have resolved it.

First things first, the example documentation: https://katex.org/docs/browser.html

Look at the "Starter template" it uses onload=, that is the first thing you must Avoid, do NOT use onload= anywhere.

Then for the autorender example: https://katex.org/docs/autorender.html

You will see that they are not loading those options through a script file:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css" integrity="sha384-Xi8rHCmBmhbuyyhbI88391ZKP2dmfnOl4rT9ZfRI7mLTdk1wblIUnrIq35nqwEvC" crossorigin="anonymous">
<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

This is infact unsafe-inline script, Even if you place it in the head. what you should do instead is place this into a file: https://github.com/Jieiku/abridge/blob/master/static/katexoptions.js

Additionally the css styleshseet file is loaded in a way that it will be render blocking, you can speed up the page load time by preloading the css file.

What I did instead was set a class for the <link rel element class="preStyle"

I then use a js file to process these, thereby making the css file no longer render blocking.

here is my prestyle.js file:

!function(){
    const items = document.querySelectorAll('.preStyle');
    items.forEach(item => {
      item.rel = 'stylesheet';
    });
}();

So long as you don't actually use any unsafe-inline then KaTeX will work with a strict CSP in place, unfortunately those without a lot of knowledge HTML, javascript, and CSP will use the examples from the katex.org documentation and wonder why KaTeX is violating their CSP policy.

For a full working example look here: https://abridge.netlify.app/overview-math/

The repository: https://github.com/Jieiku/abridge

Also you can see that this site gets a perfect observatory score: https://observatory.mozilla.org/analyze/abridge.netlify.app

@edemaine
Copy link
Member

edemaine commented Jun 8, 2022

I'm a bit confused why your solution needs to be so complicated, in particular why you need to add a class to add a rel attribute. Does the following work?

<script defer src="katex.min.js"></script>
<script defer src="auto-render.min.js"></script>
<script defer src="katexoptions.js"></script>

From MDN:

Scripts with the defer attribute will execute in the order in which they appear in the document.

If you can confirm this works, we can work on adding this to documentation.

@Jieiku
Copy link

Jieiku commented Jun 8, 2022

EDIT: I see why you came to that conclusion, I said previously I used the prestyle.js for the script element, I meant the link rel= element, sorry about that!

I am thinking maybe you did not click on the link to the site that shows me having it working? You could right click on the page and view source and see that I am already doing that:

<script defer src="https://abridge.netlify.app/katex.min.js?h=227b0d7444756f6c547b03fea4a0942699218aac0782a88f5c394893b1b306ee" integrity="sha384-ljao5I1l+8KYFXG7LNEA7DyaFvuvSCmedUf6Y6JI7LJqiu8q5dEivP2nDdFH31V4"></script>
<script defer src="https://abridge.netlify.app/mathtex-script-type.min.js?h=77e47ddc5b3af990445375441fbbbfab3f9bd368823ca10f98b2448117f6f8c5" integrity="sha384-jiBVvJ8NGGj5n7kJaiWwWp9AjC+Yh8rhZY3GtAX8yU28azcLgoRo4oukO87g7zDT"></script>
<script defer src="https://abridge.netlify.app/auto-render.min.js?h=cb7f4ca60ed5dc3e258415f8c7a3b46d4a93578a52adf83011f18a7f190e7602" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR"></script>
<script defer src="https://abridge.netlify.app/katexoptions.js?h=985b3e06694b8dcc88803ccd09b98d90d6300b1d9e2139c6ea3a2ffb20b128b3" integrity="sha384-0p9nuTTppSkKuNOiOLPLTG+Nu49i2qUHVtd5/vtGH3ntJyxh7cTZ2ZgDul8b0RiQ"></script>

however..... The following line is the line in question where I use class="preStyle" to change rel="preload" to rel="stylesheet" after the page has loaded.

<link rel="preload" as="style" class="preStyle" href="https://abridge.netlify.app/katex.min.css" integrity="sha384-ZPe7yZ91iWxYumsBEOn7ieg8q/o+qh/hQpSaPow8T6BwALcXSCS6C6fSRPIAnTQs" />

If you look at this line you will see that it shows rel="preload", this is good for downloading the file in a non render blocking manner.

Using the prestyle.js script that adds rel="stylesheet" alows you to use the downloaded css file after the page has loaded (non render blocking.)

What the script does is it changes rel="preload" to rel="stylesheet" after the page has loaded.

You could technically simplify it by changing the line to this, but it wont be deferred (It will be a render blocking element):

<link rel="stylesheet" href="https://abridge.netlify.app/katex.min.css" integrity="sha384-ZPe7yZ91iWxYumsBEOn7ieg8q/o+qh/hQpSaPow8T6BwALcXSCS6C6fSRPIAnTQs" />

Proposed Solution:

I think what you could probably do is take the javascript from prestyle.js and include it with katexoptions.js , so you might have something like this:

(you could technically include the part that sets rel=stylesheet in katex.min.js instead of katexoptions if you wanted),

<link rel="preload" as="style" class="katex-prestyle" href="katex.min.css" integrity="sha384-..." />
<script defer src="katex.min.js" integrity="sha384-..."></script>
<script defer src="mathtex-script-type.min.js" integrity="sha384-..."></script>
<script defer src="auto-render.min.js" integrity="sha384-..."></script>
<script defer src="katexoptions.js" integrity="sha384-..."></script>

katexoptions.js:

!function(){
    const items = document.querySelectorAll('.katex-prestyle');
    items.forEach(item => {
      item.rel = 'stylesheet';
    });
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
}();

The benefit of doing it this way is you could define the stylesheet either way and it would work:

<link rel="stylesheet" href="katex.min.css" integrity="sha384-..." />
<link rel="preload" as="style" class="katex-prestyle" href="katex.min.css" integrity="sha384-..." />

One would be render blocking and the other would not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants