OWASP / java-html-sanitizer

Takes third-party HTML and produces HTML that is safe to embed in your web application. Fast and easy to configure.
Other
849 stars 214 forks source link

Possible to enforce having mutliple attributes on tag? #337

Open tom-mayer opened 5 months ago

tom-mayer commented 5 months ago

Hi,

I am running into a case where I would like to enforce having two specific attributes on a tag, else the tag is illegal. As an example, <bar> should only be allowed if both attributes argh and blubb are present:

<bar argh="test"></bar>  // disallowed
<bar blubb="something" ></bar> // disallowed
<bar></bar> // disallowed
<bar argh="test" blubb="something"></bar> // allowed

I tried something like:

    private fun barRule(): PolicyFactory {
        return HtmlPolicyBuilder()
            .allowElements("bar")
            .disallowWithoutAttributes("bar")
            .allowAttributes("blubb", "argh").onElements("bar")
            .toFactory()
    }

This leads to both attributes being allowed solo, which I don't want. Is there a way to write this constraint in the builder syntax or would I have to use the allowElements with lambda function interface and implement this full manual?

I tried implementing the rule like this:

    private fun barRule(): PolicyFactory {
        return HtmlPolicyBuilder()
            .allowElements(object : ElementPolicy {
                override fun apply(name: String, attributes: MutableList<String>): String? {
                    return if (attributes.containsAll(listOf("argh", "blubb"))) {
                        name
                    } else {
                        null
                    }
                }
            }, "bar")
            .allowAttributes("argh", "blubb").onElements("bar")
            .toFactory()
    }

The one thing that is very weird is, if I sanitize <bar argh="test"></bar> with this policy, the attributes list contains two elements, argh and test (which is a value and not an attribute). Is this by design? Is there any reason why this is a string list with key/value after each other instead of a key-value Map?