matrei opened a new issue, #16459:
URL: https://github.com/apache/grails-core/issues/16459
### Summary
When `grails.views.gsp.htmlcodec` is not set, `HTMLCodec` (`grails-codecs`)
uses the HTML4 encoder (`HTML4Encoder`), the HTMLCodec implementation from
before Grails 2.3. Every generated application has opted out of it since Grails
2.3, because the application templates have set `htmlcodec: xml` for six major
versions. I suggest making the XML-safe `HTMLEncoder` the default in Grails 8,
and keeping the HTML4 encoder as an explicit opt-in.
### Current behaviour
`HTMLCodec.afterPropertiesSet()`
(`grails-codecs/src/main/groovy/org/grails/plugins/codecs/HTMLCodec.java`)
starts with the HTML4 encoder. It only switches to `HTMLEncoder` when the
setting starts with `xml` or equals `xhtml`:
```java
setUseLegacyEncoder(true); // constructor
...
if (htmlCodecSettingStr.startsWith("xml") ||
"xhtml".equalsIgnoreCase(htmlCodecSettingStr)) {
setUseLegacyEncoder(false);
}
```
At the same time:
- The application generator (`grails-forge-core`, `GrailsGsp` feature)
writes `grails.views.gsp.htmlcodec: xml` into every generated app.
- The web profile skeleton
(`grails-profiles/web/skeleton/grails-app/conf/application.yml`) also sets
`htmlcodec: xml`.
- The standalone `HTMLCodecFactory` in `grails-encoder` already uses
`HTMLEncoder`.
- The XSS prevention guide (`xssPrevention.adoc`) shows `htmlcodec: xml` in
its recommended configuration.
This has been the case for six major versions. Every application template
since Grails 2.3 (September 2013) has set `htmlcodec: xml`:
| Grails | Template | Setting |
|---|---|---|
| 2.3 – 2.5 | `grails-resources/.../conf/Config.groovy` | `htmlcodec = 'xml'
// use xml escaping instead of HTML4 escaping` |
| 3 – 7 | web profile `skeleton/grails-app/conf/application.yml` |
`htmlcodec: xml` |
| 6 – 8 | Grails Forge `GrailsGsp` feature |
`config.put("grails.views.gsp.htmlcodec", "xml")` |
Before 2.3 (2.2.0 and earlier), the template didn't set it. So for more than
12 years, the code default has only applied to apps that removed the generated
setting.
So generated apps and the standalone codec get the XML-safe encoder. Only
apps that don't set the property get the HTML4 encoder, for example apps whose
generated config was trimmed, or that were created by other means.
### Output comparison (8.0.0-RC2)
Input:
```
<a href='x'>Åsa & "Gösta" café @ `1` \ U+2028</a>
```
| Encoder | Output |
|---|---|
| `HTMLEncoder` (`xml`) | `<a href='x'>Åsa &
"Gösta" café @ `1` \ 
</a>` |
| `HTML4Encoder` (default) | `` <a href='x'>Åsa &
"Gösta" café @ `1` \ U+2028</a> `` |
In the HTML4 output, `@`, `` ` ``, `\` and U+2028 are left as they are; the
U+2028 line separator is emitted raw.
### Why `HTMLEncoder` is the better default
- **It escapes more of the characters that matter for safety.** On top of `&
< > " '`, it escapes `` ` ``, `@`, `\`, U+2028/U+2029 and the non-breaking
space, and it drops control characters. The HTML4 encoder leaves these
untouched.
- **Readable output for non-English content.** GSP output is UTF-8 by
default (`grails.views.gsp.encoding`), so turning non-ASCII letters into named
entities (`å` → `å`) only makes the page larger and harder to read.
- **Simpler and cheaper.** `HTML4Encoder` looks every character up in
Spring's private `HtmlCharacterEntityReferences` through reflection, and falls
back to calling `HtmlUtils.htmlEscape` for each character if that reflection
fails. `HTMLEncoder` is a plain `switch`.
- **Consistency.** The default would match what the generator writes, what
the guide recommends and what `grails-encoder` already does.
### Proposed change
1. Default `HTMLCodec` to `HTMLEncoder`.
2. Add an explicit value to opt back in to the HTML4 encoder, e.g.
`grails.views.gsp.htmlcodec: html4`. Keep `xml` and `xhtml` working as they do
today.
3. Update the description of `grails.views.gsp.htmlcodec` in `grails-gsp`'s
`additional-spring-configuration-metadata.json`, and the "HTMLCodec" section in
`grails-doc/src/en/guide/security/codecs.adoc`. The section says "HTMLCodec
defaults to HTML4 style escaping"; it also says HTML encoding "does not
re-encode apostrophe/single quote", which is out of date, since both encoders
now escape `'` as `'`.
4. Remove `htmlcodec: xml` from the generator (`GrailsGsp`) and the web
profile skeleton, since it becomes the default.
5. Add a note to the Grails 8 upgrade guide.
`HTML4Codec` stays available for per-expression use (`encodeAsHTML4()`).
### Compatibility
The change affects apps that rely on the current default:
- Escaped output changes: non-ASCII letters are no longer entities, and `@`,
`` ` ``, `\` are now escaped. Tests that assert exact markup may need updating.
- Apps that serve GSP pages in a non-UTF-8 charset (e.g. ISO-8859-1), and
rely on entities for characters outside that charset, should set
`grails.views.gsp.htmlcodec: html4`.
Apps that set `htmlcodec: xml`, as the generator and the web profile do, are
not affected.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]