mirror of
https://github.com/golang/go
synced 2024-11-26 19:51:17 -07:00
text/template: harden JSEscape to also escape ampersand and equal
Ampersand and equal are not dangerous in a JS/JSString context but they might cause issues if interpolated in HTML attributes. This change makes it harder to introduce XSS by misusing escaping. Thanks to t1ddl3r <t1ddl3r@gmail.com> for reporting this common misuse scenario. Fixes #35665 Change-Id: Ice6416477bba4cb2ba2fe2cfdc20e027957255c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/207637 Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Mike Samuel <mikesamuel@gmail.com> Reviewed-by: Andrew Bonventre <andybons@golang.org> Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
This commit is contained in:
parent
f4a8bf1283
commit
94e9a5e19b
@ -116,9 +116,9 @@ func Example_escape() {
|
|||||||
// "Fran & Freddie's Diner" <tasty@example.com>
|
// "Fran & Freddie's Diner" <tasty@example.com>
|
||||||
// "Fran & Freddie's Diner" <tasty@example.com>
|
// "Fran & Freddie's Diner" <tasty@example.com>
|
||||||
// "Fran & Freddie's Diner"32<tasty@example.com>
|
// "Fran & Freddie's Diner"32<tasty@example.com>
|
||||||
// \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E
|
// \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
|
||||||
// \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E
|
// \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
|
||||||
// \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E
|
// \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E
|
||||||
// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
|
// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -909,6 +909,8 @@ func TestJSEscaping(t *testing.T) {
|
|||||||
{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
|
{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
|
||||||
{"unprintable \uFDFF", `unprintable \uFDFF`},
|
{"unprintable \uFDFF", `unprintable \uFDFF`},
|
||||||
{`<html>`, `\x3Chtml\x3E`},
|
{`<html>`, `\x3Chtml\x3E`},
|
||||||
|
{`no = in attributes`, `no \x3D in attributes`},
|
||||||
|
{`' does not become HTML entity`, `\x26#x27; does not become HTML entity`},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
s := JSEscapeString(tc.in)
|
s := JSEscapeString(tc.in)
|
||||||
|
@ -642,6 +642,8 @@ var (
|
|||||||
jsQuot = []byte(`\"`)
|
jsQuot = []byte(`\"`)
|
||||||
jsLt = []byte(`\x3C`)
|
jsLt = []byte(`\x3C`)
|
||||||
jsGt = []byte(`\x3E`)
|
jsGt = []byte(`\x3E`)
|
||||||
|
jsAmp = []byte(`\x26`)
|
||||||
|
jsEq = []byte(`\x3D`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
|
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
|
||||||
@ -670,6 +672,10 @@ func JSEscape(w io.Writer, b []byte) {
|
|||||||
w.Write(jsLt)
|
w.Write(jsLt)
|
||||||
case '>':
|
case '>':
|
||||||
w.Write(jsGt)
|
w.Write(jsGt)
|
||||||
|
case '&':
|
||||||
|
w.Write(jsAmp)
|
||||||
|
case '=':
|
||||||
|
w.Write(jsEq)
|
||||||
default:
|
default:
|
||||||
w.Write(jsLowUni)
|
w.Write(jsLowUni)
|
||||||
t, b := c>>4, c&0x0f
|
t, b := c>>4, c&0x0f
|
||||||
@ -704,7 +710,7 @@ func JSEscapeString(s string) string {
|
|||||||
|
|
||||||
func jsIsSpecial(r rune) bool {
|
func jsIsSpecial(r rune) bool {
|
||||||
switch r {
|
switch r {
|
||||||
case '\\', '\'', '"', '<', '>':
|
case '\\', '\'', '"', '<', '>', '&', '=':
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return r < ' ' || utf8.RuneSelf <= r
|
return r < ' ' || utf8.RuneSelf <= r
|
||||||
|
Loading…
Reference in New Issue
Block a user