microcosm-cc / bluemonday

bluemonday: a fast golang HTML sanitizer (inspired by the OWASP Java HTML Sanitizer) to scrub user generated content of XSS
https://github.com/microcosm-cc/bluemonday
BSD 3-Clause "New" or "Revised" License
3.12k stars 176 forks source link

How would I go about letting only a specific class through? #131

Closed clarencefoy closed 2 years ago

clarencefoy commented 3 years ago

I want to make sure that only elements using a specific rich text formatting class get through the sanitiser. In this case, using the quill text editor, I have the following classes which could be part of some text a user enters, that I have tried enabling via the following rules:

    p.AllowAttrs("class").Matching(regexp.MustCompile(`^ql-size-huge-`)).OnElements("span", "a", "s", "u", "em", "strong")
    p.AllowAttrs("class").Matching(regexp.MustCompile(`^ql-size-large-`)).OnElements("span", "a", "s", "u", "em", "strong")
    p.AllowAttrs("class").Matching(regexp.MustCompile(`^ql-size-small-`)).OnElements("span", "a", "s", "u", "em", "strong")

I have tried a few variations of this, such as:

    p.AllowAttrs("class").Matching(regexp.MustCompile(`"ql-size-huge"`)).OnElements("span", "a", "s", "u", "em", "strong")

or

    p.AllowAttrs("class").Matching(regexp.MustCompile(`class="ql-size-huge"`)).OnElements("span", "a", "s", "u", "em", "strong")

But it would appear that none of these are let through. The documentation does not provide a specific example for defining a specific class as being allowed, so I was wondering how I might achieve this?

Many thanks

buro9 commented 2 years ago

Are you sure these don't work?

I wrote up a test and added it to sanitize_test.go to check it... and it passes fine.

func TestIssue131(t *testing.T) {
    tests := []test{
        {
            in:       `<em class="ql-size-huge">content</em>`,
            expected: `<em class="ql-size-huge">content</em>`,
        },
        {
            in:       `<em class="ql-size-large">content</em>`,
            expected: `<em class="ql-size-large">content</em>`,
        },
        {
            in:       `<em class="ql-size-small">content</em>`,
            expected: `<em class="ql-size-small">content</em>`,
        },
        {
            in:       `<em class="ql-size-random">content</em>`,
            expected: `<em>content</em>`,
        },
        {
            in:       `<span class="ql-size-large">content</span>`,
            expected: `<span class="ql-size-large">content</span>`,
        },
    }

    p := UGCPolicy()

    p.AllowAttrs("class").Matching(regexp.MustCompile(`^ql-size-(huge|large|small)$`)).OnElements("em", "span")

    // These tests are run concurrently to enable the race detector to pick up
    // potential issues
    wg := sync.WaitGroup{}
    wg.Add(len(tests))
    for ii, tt := range tests {
        go func(ii int, tt test) {
            out := p.Sanitize(tt.in)
            if out != tt.expected {
                t.Errorf(
                    "test %d failed;\ninput   : %s\noutput  : %s\nexpected: %s",
                    ii,
                    tt.in,
                    out,
                    tt.expected,
                )
            }
            wg.Done()
        }(ii, tt)
    }
    wg.Wait()
}