Skip to content

Manipulation: Avoid concatenating strings in buildFragment #4724

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 10, 2020

Conversation

mgol
Copy link
Member

@mgol mgol commented May 31, 2020

Summary

Concatenating HTML strings in buildFragment is a possible security risk as it
creates an opportunity of escaping the concatenated wrapper. It also makes it
impossible to support secure HTML wrappers like
trusted types. It's safer to create wrapper
elements using document.createElement & appendChild.

The previous way was needed in jQuery <4 because IE <10 doesn't accept table
parts set via innerHTML, even if the element which contents are set is
a proper table element, e.g.:

tr.innerHTML = "<td></td>";

The whole structure needs to be passed in one HTML string. jQuery 4 drops
support for IE <11 so this is no longer an issue; in older version we'd have to
duplicate the code paths.

IE <10 needed to have <option> elements wrapped in
<select multiple="multiple"> but we no longer need that on master which makes
the document.createElement way shorter as we don't have to call
setAttribute.

jQuery 1.x sometimes needed to have more than one element in the wrapper that
would precede parts wrapping HTML input so descending needed to use lastChild.
Since all wrappers are single-element now, we can use firstChild which
compresses better as it's used in other places in the code as well.

All these improvements, apart from making logic more secure, decrease the
gzipped size by 55 bytes.

Ref gh-4409
Ref angular/angular.js#17028

Checklist

Sorry, something went wrong.

@mgol mgol added this to the 4.0.0 milestone May 31, 2020
@mgol mgol requested a review from timmywil May 31, 2020 21:57
@mgol mgol self-assigned this May 31, 2020
@mgol mgol force-pushed the secure-buildFragment branch from b9588a7 to 8a24861 Compare May 31, 2020 21:59
Copy link
Member

@dmethvin dmethvin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation! LGTM and saves space so double good.

@mgol mgol force-pushed the secure-buildFragment branch 2 times, most recently from 876c924 to da74354 Compare June 1, 2020 16:25
@mgol mgol requested a review from gibson042 June 1, 2020 16:32
@koto
Copy link

koto commented Jun 2, 2020

Looks great, thanks Michał!

@mgol mgol force-pushed the secure-buildFragment branch from da74354 to 872affd Compare June 5, 2020 17:00
Concatenating HTML strings in buildFragment is a possible security risk as it
creates an opportunity of escaping the concatenated wrapper. It also makes it
impossible to support secure HTML wrappers like
[trusted types](https://web.dev/trusted-types/). It's safer to create wrapper
elements using `document.createElement` & `appendChild`.

The previous way was needed in jQuery <4 because IE <10 doesn't accept table
parts set via `innerHTML`, even if the element which contents are set is
a proper table element, e.g.:
```js
tr.innerHTML = "<td></td>";
```
The whole structure needs to be passed in one HTML string. jQuery 4 drops
support for IE <11 so this is no longer an issue; in older version we'd have to
duplicate the code paths.

IE <10 needed to have `<option>` elements wrapped in
`<select multiple="multiple">` but we no longer need that on master which makes
the `document.createElement` way shorter as we don't have to call
`setAttribute`.

jQuery 1.x sometimes needed to have more than one element in the wrapper that
would precede parts wrapping HTML input so descending needed to use `lastChild`.
Since all wrappers are single-element now, we can use `firstChild` which
compresses better as it's used in other places in the code as well.

All these improvements, apart from making logic more secure, decrease the
gzipped size by 55 bytes.

Ref jquerygh-4409
Ref angular/angular.js#17028
@mgol mgol force-pushed the secure-buildFragment branch from 872affd to bb726fc Compare June 6, 2020 20:52
mgol and others added 2 commits June 8, 2020 19:54
@mgol
Copy link
Member Author

mgol commented Jun 8, 2020

@gibson042 Nice catch with the document -> context switch, somehow our unit tests don't check for it. This is now at -58 bytes so we saved an additional 3, nice!

Please have another look.

Copy link
Member

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@mgol mgol removed the Needs review label Jun 10, 2020
@mgol mgol merged commit 9c98e4e into jquery:master Jun 10, 2020
@mgol mgol deleted the secure-buildFragment branch June 10, 2020 14:13
mgol added a commit to mgol/jquery that referenced this pull request Sep 13, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit to mgol/jquery that referenced this pull request Sep 14, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit to mgol/jquery that referenced this pull request Sep 17, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit to mgol/jquery that referenced this pull request Sep 23, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit to mgol/jquery that referenced this pull request Sep 29, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit to mgol/jquery that referenced this pull request Sep 29, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
jquerygh-4642 and jquerygh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes jquerygh-4409
Ref jquerygh-4642
Ref jquerygh-4724
mgol added a commit that referenced this pull request Sep 30, 2021
This ensures HTML wrapped in TrustedHTML can be used as an input to jQuery
manipulation methods in a way that doesn't violate the
`require-trusted-types-for` Content Security Policy directive.
This commit builds on previous work needed for trusted types support, including
gh-4642 and gh-4724.

One restriction is that while any TrustedHTML wrapper should work as input
for jQuery methods like `.html()` or `.append()`, for passing directly to the
`jQuery` factory the string must start with `<` and end with `>`; no trailing
or leading whitespaces are allowed. This is necessary as we cannot parse out
a part of the input for further construction; that would violate the CSP rule -
and that's what's done to HTML input not matching these constraints.

No trusted types API is used explicitly in source; the majority of the work is
ensuring we don't pass the input converted to string to APIs that would
eventually assign it to `innerHTML`. This extra cautiousness is caused by the
API being Blink-only, at least for now.

The ban on passing strings to `innerHTML` means support tests relying on such
assignments are impossible. We don't currently have such tests on the `main`
branch but we used to have many of them in the 3.x & older lines. If there's
a need to re-add such a test, we'll need an escape hatch to skip them for apps
needing CSP-enforced TrustedHTML.

See https://web.dev/trusted-types/ for more information about TrustedHTML.

Fixes gh-4409
Closes gh-4927
Ref gh-4642
Ref gh-4724
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

5 participants