Jekyll2018-10-23T22:09:42+00:00https://hen.ne.ke/Fabian HennekeMath grad student & IT security enthusiast{"twitter"=>"fhenneke"}jekyll-mathjax-csp: Uniting MathJax, Jekyll and a Strict CSP2018-02-04T20:48:00+00:002018-02-04T20:48:00+00:00https://hen.ne.ke/2018/02/04/jekyll-mathjax-csp-uniting-mathjax-jekyll-and-a-strict-csp<p>In our quest to vanquish the foe that is XSS and for an A+ rating from the <a href="https://observatory.mozilla.org">Mozilla Observatory</a>, today, we will be rendering mathematical formulas in a fast and secure fashion.</p>
<p><strong>TL;DR:</strong> If you want to include math in your Jekyll blog that does neither tax your reader’s CPUs nor force you to forego a strict CSP, try out my new plugin <a href="https://github.com/FabianHenneke/jekyll-mathjax-csp/"><code class="highlighter-rouge">jekyll-mathjax-csp</code></a>.</p>
<h2 id="motivation">Motivation</h2>
<p>This blog doubles as my personal testbed for web technologies. My aim is to try out new techniques without compromising on aspects of security. After all, how could I wholeheartedly recommend Content Security Policies, HSTS, usage of SRI and all the other web security features without having them set up on my own site? And even the excuse that this page is statically generated and thus will never be exposed to much harm doesn’t hold up, as <a href="https://staticman.net/">comments</a>, <a href="https://hen.ne.ke/lab-list/">hosted JavaScript experiments</a> and <a href="https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5">potentially malicious dependencies</a> make for quite some dymanic content on this otherwise static web page.</p>
<h2 id="mathjax--beautiful-math-in-all-browsers">MathJax — “Beautiful Math in All Browsers”</h2>
<p><a href="https://www.mathjax.org/">MathJax</a> is a JavaScript library that renders mathematical formulas expressed in TeX (or MathML or ASCIIMath) directly in the user’s browser. It supports a wide variety of TeX commands, features typography that is (almost as) beautiful as that produced by native (La)TeX and puts effort into making the rendered output accessible.</p>
<h3 id="client-side-rendering--its-complicated">Client-Side Rendering — “It’s complicated”</h3>
<p>While MathJax is arguably the gold standard for rendering math on the web, it also has some disadvantages: Since the rendering happens client-side, it causes high CPU load on the user’s device, which can be overwhelming especially on cheaper mobile clients. At best, it will take a couple of seconds to render a math-heavy page.</p>
<p>Another potential problem of client-side MathJax rendering is that two of the three supported output formats, SVG and HTML, requires lots of inline <code class="highlighter-rouge">style</code> attributes. As a result, a CSP on a page relying on MathJax necessarily has to include <code class="highlighter-rouge">style-src: 'unsafe-inline'</code>. While being much less dangerous than <code class="highlighter-rouge">script-src: 'unsafe-inline'</code>, this directive is still able to <a href="https://www.nds.rub.de/media/emma/veroeffentlichungen/2012/08/16/scriptlessAttacks-ccs2012.pdf">inflict damage</a>, including but not limited to blatantly defacing, covertly changing and leaking information from a page.</p>
<p>The remaining output format, MathML, was created as a “native” markup language for math on the web, but has never really caught on: At the moment, only Firefox has full support for it, meaning that it cannot be used without providing a fallback to other formats. It certainly didn’t help MathML that it is quite complex, frequently making an appearance in arcane XSS vectors. Did you know that <a href="https://html5sec.org/#143">MathML can be used to build links that will always leak <code class="highlighter-rouge">window.opener</code></a>? Or that it can be used to <a href="https://html5sec.org/#130">execute JavaScript without using an <code class="highlighter-rouge">href</code> or event listener attribute</a>? Since such attack vectors could also be exploited by MathML rendered from a TeX formula, MathJax offers a <a href="https://docs.mathjax.org/en/latest/safe-mode.html">Safe mode</a> that is highly recommended if you use MathJax to render user-supplied TeX.</p>
<p>But even without rendering to MathML, client-side MathJax on a page with a CSP that permits the use of <code class="highlighter-rouge">eval()</code> has gotcha potential. When MathJax loads on a page for the first time, it looks for specially marked <code class="highlighter-rouge"><script></code> tags containing custom configurations. While these scripts usually consist of a single call to <code class="highlighter-rouge">MathJax.Hub.Config</code>, they can contain arbitrary JavaScript that is executed by MathJax using <code class="highlighter-rouge">eval()</code>. The result is an <code class="highlighter-rouge">unsafe-eval</code> to <code class="highlighter-rouge">unsafe-inline</code> CSP bypass with the restriction that inline scripts have to be injected into the page before MathJax is loaded. You can experience this bypass in action in <a href="/labs/mathjax-csp/">this lab</a>.</p>
<h3 id="server-side-rendering--svg-to-the-rescue">Server-Side Rendering — “SVG to the Rescue”</h3>
<p>Given the restrictions that client-side MathJax imposes on the strictness of the CSP and the CPU load it causes on the reader’s device, I decided to try out server-side rendering. The npm package <a href="https://github.com/mathjax/MathJax-node"><code class="highlighter-rouge">mathjax-node</code></a> can be used from Node.js to pre-render TeX formulas into either SVG, HTML or MathML. Together with the package <a href="https://github.com/pkra/mathjax-node-page/"><code class="highlighter-rouge">mathjax-node-page</code></a>, entire pages of TeX math can be rendered automatically, either from Node.js or via the CLI command <code class="highlighter-rouge">mjpage</code>.</p>
<p>While in HTML and MathML mode the server-based approach suffers from the same CSP-related problems as discussed above, the SVG output made me hopeful: Its usage of inline styles is limited to a single fixed <code class="highlighter-rouge"><style></code> element in the head and one <code class="highlighter-rouge">style</code> attribute per SVG in the output. As this appears to be a somewhat manageable amount of inline activity and since SVG is a widely supported and high-quality output format for mathematical typography, I decided to wrap everything into a CSP-aware Jekyll plugin.</p>
<h2 id="jekyll-mathjax-csp">jekyll-mathjax-csp</h2>
<p><a href="https://github.com/FabianHenneke/jekyll-mathjax-csp"><code class="highlighter-rouge">jekyll-mathjax-csp</code></a> is a Jekyll plugin that automatically renders math picked up by the kramdown parser by running it through <code class="highlighter-rouge">mathjax-node</code>. It collects all newly added inline styles and turns them into proper CSS classes, which are then injected into a single inline <code class="highlighter-rouge"><style></code> element in the head of the page. The hash over this element’s content is computed and the collection of all such hashes can either automatically (via the <code class="highlighter-rouge"><span class="p">{</span><span class="err">%</span><span class="w"> </span><span class="err">mathjax_csp_sources</span><span class="w"> </span><span class="err">%</span><span class="p">}</span></code> tag) or manually (copied from a message shown during the build) be added to the site’s CSP.</p>
<h3 id="usage">Usage</h3>
<p>Head over to <a href="https://github.com/FabianHenneke/jekyll-mathjax-csp/blob/master/README.md">the README</a> for detailed usage instructions.</p>
<h3 id="issues">Issues</h3>
<p>If you experience any issues with <code class="highlighter-rouge">jekyll-mathjax-csp</code> or want to make a feature request, please <a href="https://github.com/FabianHenneke/jekyll-mathjax-csp/issues/new">create an issue on GitHub</a>.</p>
<h3 id="examples">Examples</h3>
<p>Inline math: <code class="highlighter-rouge">$$\pi_3(S^2) \cong \mathbb{Z}$$</code> <script type="math/tex">\leadsto \pi_3(S^2) \cong \mathbb{Z}</script></p>
<p>Display math:</p>
<div class="language-tex highlighter-rouge"><pre class="highlight"><code><span class="p">$$</span><span class="nv">\operatorname</span><span class="p">{</span><span class="nb">ind</span><span class="p">}</span><span class="nb"> P </span><span class="o">=</span><span class="nb"> </span><span class="nv">\int</span><span class="p">_{</span><span class="nb">X</span><span class="p">}</span><span class="nv">\operatorname</span><span class="p">{</span><span class="nb">ch</span><span class="p">}</span><span class="nb"> </span><span class="nv">\sigma</span><span class="o">(</span><span class="nb">P</span><span class="o">)</span><span class="nb"> </span><span class="nv">\cdot</span><span class="nb"> </span><span class="nv">\operatorname</span><span class="p">{</span><span class="nb">Td</span><span class="p">}</span><span class="o">(</span><span class="nb">TX </span><span class="nv">\otimes</span><span class="nb"> </span><span class="nv">\mathbb</span><span class="p">{</span><span class="nb">C</span><span class="p">}</span><span class="o">)</span><span class="p">$$</span>
</code></pre>
</div>
<script type="math/tex; mode=display">\leadsto \operatorname{ind} P = \int_{X}\operatorname{ch} \sigma(P) \cdot \operatorname{Td}(TX \otimes \mathbb{C})</script>
<p>CSP sources for all the MathJax-related styles on <a href="https://hen.ne.ke">hen.ne.ke</a>:</p>
<p><code class="highlighter-rouge"><span class="p">{</span><span class="err">%</span><span class="w"> </span><span class="err">mathjax_csp_sources</span><span class="w"> </span><span class="err">%</span><span class="p">}</span></code></p>
<p><script type="math/tex">\leadsto</script> <code class="highlighter-rouge">'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='</code></p>{"twitter"=>"fhenneke"}In our quest to vanquish the foe that is XSS and for an A+ rating from the Mozilla Observatory, today, we will be rendering mathematical formulas in a fast and secure fashion.