ACE inserts several inline <style>
tags into the <head>
. For example, the virtual renderer imports ace_editor.css
and themes import their own CSS.
This is a problem for pages that want to run a Content Security Policy. Those inline <style>
tags must have either a nonce (generated by the server, which ace.js
wouldn't possibly know about) or a hash.
I don't have a clear suggestion, but here are some ideas:
<style>
tags to the DOM, but instead exposes them on the filesystem so application authors can include them via <link>
tags or @import
directives.<link>
tags referencing them instead of <style>
tags.Chrome, as of version 46, no longer supports the unsafe-inline
option because it's too broad an attack vector, so that isn't an option.
OWASP has some good information about why inline <style>
tags are dangerous.
I've calculated hashes for
XYBtnr/s6KimmpqYM4EDrs1C2bYyBk40b3LwJcrAv8s=
)Dn0vMZLidJplZ4cSlBMg/F5aa7Vol9dBMHzBF4fGEtk=
)sA0hymKbXmMTpnYi15KmDw4u6uRdLXqHyoYIaORFtjU=
)0U0G1g5NVv9EirSrnNcK2svBrTzHeoUjWt4/Vcf/iuY=
)That silences the errors while initializing the library.
But when ACE renders text, it uses .innerHTML = ...
with a string that often includes a style='...'
attribute. For example, in ace/layer/marker
and several methods in ace/layer/text
. These cannot be whitelisted even with a SHA256 hash of the style='...'
contents. Additionally, their style='..'
contents are dynamically generated, such as in <div class='ace_selection ace_br12' style='height:16px;width:208.83625px;top:64px;left:4px;'>
when I click on a row. There's no way to exhaustively enumerate those in a page's CSP.
It may help to create HTMLElement
s and set their style
properties instead of using innerHTML
to build up DOM.
The two workarounds for css issue are relatively straightforward to implement, however stopping use of innerHtml is a major change which we can't implement quickly
however stopping use of innerHtml is a major change which we can't implement quickly
Is that something you'd be interested in, though? It's not something we've prioritized yet, but our team might be able to work on this. Improving XSS protection is very important to us.
I have a prototype for removing innerHTML at https://github.com/ajaxorg/ace/pull/3372/files, unfortunately that branch is slower than v1.2.8 when running scroll benchmark from https://github.com/ajaxorg/ace/blob/master/tool/perf-test.html.
If you know a way of optimizing dom calls or know a better way to benchmark, please let us know.
I'll definitely try the use-dom-api branch. Thanks!
If ACE offers CSP support, it would be an advantage over the alternative solutions like CodeMirror.
If ACE offers CSP support, it would be an advantage over the alternative solutions like CodeMirror.
Absolutely.
Are there any plans to extend the work in https://github.com/ajaxorg/ace/pull/3609 to the marker layer too, @fjakobs?
@lol768 #3609 removed all uses of innerHTML, now we only need to find a solution for css.
now we only need to find a solution for css
While style='foo: bar;'
is a security risk, el.style.foo = 'bar'
should not be and is allowed by even strict Content Security Policies.
@jamesarosen i mean solution for style elements, both providing hashes and creating separate css files require too much changes. Would a solution using nonce-source work for you?
Something like:
"Content-Security-Policy":
"default-src 'self' blob: ; style-src 'self' 'nonce-<secretNumber>'; img-src 'self' data:"
ace.config.set("cspToken", <secretNumber>)
ace.edit(...)
so that Ace can set style.nonce
when creating the element in https://github.com/ajaxorg/ace/blob/master/lib/ace/lib/dom.js#L191
From the CSP level 2 spec,
If the policy contains a nonce-source expression, the server MUST generate a fresh value for the nonce-value directive at random and independently each time it transmits a policy. The generated value SHOULD be at least 128 bits long (before encoding), and generated via a cryptographically secure random number generator. This requirement ensures that the nonce-value is difficult for an attacker to predict.
Note: Using a nonce to whitelist inline script or style is less secure than not using a nonce, as nonces override the restrictions in the directive in which they are present. An attacker who can gain access to the nonce can execute whatever script they like, whenever they like. That said, nonces provide a substantial improvement over 'unsafe-inline' when layering a content security policy on top of old code. When considering 'unsafe-inline', authors are encouraged to consider nonces (or hashes) instead.
Because nonces have to be generated on every request, it's not possible to put
ace.config.set("cspToken", <secretNumber>)
in a separate .js
file. It would have to be in the including HTML:
<script type='application/javascript' nonce='nonceA'>
ace.config.set('cspToken', nonceB)
</script>
But an attacker who can read ace.config
then has access to that value and could use it to execute code on the page.
Most helpful comment
I've calculated hashes for
XYBtnr/s6KimmpqYM4EDrs1C2bYyBk40b3LwJcrAv8s=
)Dn0vMZLidJplZ4cSlBMg/F5aa7Vol9dBMHzBF4fGEtk=
)sA0hymKbXmMTpnYi15KmDw4u6uRdLXqHyoYIaORFtjU=
)0U0G1g5NVv9EirSrnNcK2svBrTzHeoUjWt4/Vcf/iuY=
)That silences the errors while initializing the library.
But when ACE renders text, it uses
.innerHTML = ...
with a string that often includes astyle='...'
attribute. For example, inace/layer/marker
and several methods inace/layer/text
. These cannot be whitelisted even with a SHA256 hash of thestyle='...'
contents. Additionally, theirstyle='..'
contents are dynamically generated, such as in<div class='ace_selection ace_br12' style='height:16px;width:208.83625px;top:64px;left:4px;'>
when I click on a row. There's no way to exhaustively enumerate those in a page's CSP.It may help to create
HTMLElement
s and set theirstyle
properties instead of usinginnerHTML
to build up DOM.