logoalt Hacker News

entunotoday at 1:29 PM13 repliesview on HN

This kind of thing always makes me nervous, because you end with a mix of methods where you can (supposedly) pass arbitrary user input to them and they'll safely handle it, and methods where you can't do that without introducing vulnerabilities - but it's not at all clear which is which from the names. Ideally you design that in from the state, so any dangerous functions are very clearly dangerous from the name. But you can't easily do that down the line.

I'm also rather sceptical of things that "sanitise" HTML, both because there's a long history of them having holes, and because it's not immediately clear what that means, and what exactly is considered "safe".


Replies

jncratontoday at 2:03 PM

You are right that the concept of "safe" is nebulous, but the goal here is specifically to be XSS-safe [1]. Elements or properties that could allow scripts to execute are removed. This functionality lives in the user agent and prevents adding unsafe elements to the DOM itself, so it should be easier to get correct than a string-to-string sanitizer. The logic of "is the element currently being added to the DOM a <script>" is fundamentally easier to get right than "does this HTML string include a script tag".

[1] https://developer.mozilla.org/en-US/docs/Web/API/Element/set...

show 2 replies
cxrtoday at 8:34 PM

> it's not at all clear which is which from the names. Ideally you design that in from the [start]

It was, and there is: setting elementNode.textContent is safe for untrusted inputs, and setting elementNode.innerHTML is unsafe for untrusted inputs. The former will escape everything, and the latter won't escape anything.

You are right that these "sanitizers" are fundamentally confused:

> "HTML sanitization" is never going to be solved because it's not solvable.¶ There's no getting around knowing whether or any arbitrary string is legitimate markup from a trusted source or some untrusted input that needs to be treated like text. This is a hard requirement.

<https://news.ycombinator.com/item?id=46222923>

The Web platform folks who are responsible for getting fundamental APIs standardized and implemented natively are in a position to know better, and they should know better. This API should not have made it past proposal stage and should not have been added to browsers.

show 1 reply
snowhaletoday at 2:04 PM

the browser-native Sanitizer API has one advantage the library approaches don't: it uses the same HTML parser the browser uses to render. libraries like DOMPurify parse in a separate context then re-serialize, and historically that round-trip is where most bypasses came from. when the sanitizer and the renderer share the same parser, mutation XSS attacks have nowhere to hide.

show 2 replies
Cthulhu_today at 3:37 PM

Ideally you should be able to set a global property somewhere (as a web developer) that disallows outdated APIs like `innerHTML`, but with the Big Caveat that your website will not work on browsers older than X. But maybe there's web standards for that already, backup content if a browser is considered outdated.

show 3 replies
voxic11today at 1:43 PM

The idea is you wouldn't mix innerHTML and setHTML, you would eliminate all usage of innerHTML and use the new setHTMLUnsafe if you needed the old functionality.

show 4 replies
jaffathecaketoday at 2:54 PM

fwiw, if you serve your page with:

Content-Security-Policy: require-trusted-types-for 'script'

…then it blocks you from passing regular strings to the methods that don't sanitize.

DoctorOWtoday at 1:59 PM

They do link the default configuration for "safe": https://wicg.github.io/sanitizer-api/#built-in-safe-default-...

But I agree, my default approach has usually been to only use innerText if it has untrusted content:

So if their demo is this:

    container.SetHTML(`<h1>Hello, {name}</h1>`);
Mine would be:

    let greetingHeader = container.CreateElement("h1");
    greetingHeader.innerText = `Hello, {name}`;
show 1 reply
HWR_14today at 5:30 PM

That's why I only allow user input of alphanumeric ascii characters. No need to worry about sanitation then, and you can just remove all the characters that don't match.

(It's a joke, but it is also 100% XSS, SQL injection, etc. safe and future proof)

thaumasiotestoday at 8:27 PM

> I'm also rather sceptical of things that "sanitise" HTML, both because there's a long history of them having holes, and because it's not immediately clear what that means, and what exactly is considered "safe".

What is safe depends on where the sanitized HTML is going, on what you're doing with it.

It isn't possible to "sanitize HTML" after collecting it so that, when you use it in the future, it will be safe. "Safe" is defined by the use.

But it is possible to sanitize it before using it, when you know what the use will be.

noduermetoday at 2:07 PM

Some sanitization is better than none? If you're relying on the browser to handle it for you, you're already in a lot of trouble.

post-ittoday at 1:59 PM

realSetSafeHTML()

onion2ktoday at 4:35 PM

it's not at all clear which is which from the names

There's setHTML and setHTMLUnsafe. That seems about as clear as you can get.

show 2 replies