crypto: Escape JSON text (#10794)
Escape the JSON keys+values from the context. We do not add the HTML escapes, since that is an extra escape level not mandatory for JSON.master
parent
6bfa162342
commit
e8ce348da1
@ -0,0 +1,200 @@ |
||||
// MinIO Cloud Storage, (C) 2020 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package crypto |
||||
|
||||
import ( |
||||
"bytes" |
||||
"unicode/utf8" |
||||
) |
||||
|
||||
// Adapted from Go stdlib.
|
||||
|
||||
var hexTable = "0123456789abcdef" |
||||
|
||||
// EscapeStringJSON will escape a string for JSON and write it to dst.
|
||||
func EscapeStringJSON(dst *bytes.Buffer, s string) { |
||||
start := 0 |
||||
for i := 0; i < len(s); { |
||||
if b := s[i]; b < utf8.RuneSelf { |
||||
if htmlSafeSet[b] { |
||||
i++ |
||||
continue |
||||
} |
||||
if start < i { |
||||
dst.WriteString(s[start:i]) |
||||
} |
||||
dst.WriteByte('\\') |
||||
switch b { |
||||
case '\\', '"': |
||||
dst.WriteByte(b) |
||||
case '\n': |
||||
dst.WriteByte('n') |
||||
case '\r': |
||||
dst.WriteByte('r') |
||||
case '\t': |
||||
dst.WriteByte('t') |
||||
default: |
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
// If escapeHTML is set, it also escapes <, >, and &
|
||||
// because they can lead to security holes when
|
||||
// user-controlled strings are rendered into JSON
|
||||
// and served to some browsers.
|
||||
dst.WriteString(`u00`) |
||||
dst.WriteByte(hexTable[b>>4]) |
||||
dst.WriteByte(hexTable[b&0xF]) |
||||
} |
||||
i++ |
||||
start = i |
||||
continue |
||||
} |
||||
c, size := utf8.DecodeRuneInString(s[i:]) |
||||
if c == utf8.RuneError && size == 1 { |
||||
if start < i { |
||||
dst.WriteString(s[start:i]) |
||||
} |
||||
dst.WriteString(`\ufffd`) |
||||
i += size |
||||
start = i |
||||
continue |
||||
} |
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
if c == '\u2028' || c == '\u2029' { |
||||
if start < i { |
||||
dst.WriteString(s[start:i]) |
||||
} |
||||
dst.WriteString(`\u202`) |
||||
dst.WriteByte(hexTable[c&0xF]) |
||||
i += size |
||||
start = i |
||||
continue |
||||
} |
||||
i += size |
||||
} |
||||
if start < len(s) { |
||||
dst.WriteString(s[start:]) |
||||
} |
||||
} |
||||
|
||||
// htmlSafeSet holds the value true if the ASCII character with the given
|
||||
// array position can be safely represented inside a JSON string, embedded
|
||||
// inside of HTML <script> tags, without any additional escaping.
|
||||
//
|
||||
// All values are true except for the ASCII control characters (0-31), the
|
||||
// double quote ("), the backslash character ("\"), HTML opening and closing
|
||||
// tags ("<" and ">"), and the ampersand ("&").
|
||||
var htmlSafeSet = [utf8.RuneSelf]bool{ |
||||
' ': true, |
||||
'!': true, |
||||
'"': false, |
||||
'#': true, |
||||
'$': true, |
||||
'%': true, |
||||
'&': false, |
||||
'\'': true, |
||||
'(': true, |
||||
')': true, |
||||
'*': true, |
||||
'+': true, |
||||
',': true, |
||||
'-': true, |
||||
'.': true, |
||||
'/': true, |
||||
'0': true, |
||||
'1': true, |
||||
'2': true, |
||||
'3': true, |
||||
'4': true, |
||||
'5': true, |
||||
'6': true, |
||||
'7': true, |
||||
'8': true, |
||||
'9': true, |
||||
':': true, |
||||
';': true, |
||||
'<': false, |
||||
'=': true, |
||||
'>': false, |
||||
'?': true, |
||||
'@': true, |
||||
'A': true, |
||||
'B': true, |
||||
'C': true, |
||||
'D': true, |
||||
'E': true, |
||||
'F': true, |
||||
'G': true, |
||||
'H': true, |
||||
'I': true, |
||||
'J': true, |
||||
'K': true, |
||||
'L': true, |
||||
'M': true, |
||||
'N': true, |
||||
'O': true, |
||||
'P': true, |
||||
'Q': true, |
||||
'R': true, |
||||
'S': true, |
||||
'T': true, |
||||
'U': true, |
||||
'V': true, |
||||
'W': true, |
||||
'X': true, |
||||
'Y': true, |
||||
'Z': true, |
||||
'[': true, |
||||
'\\': false, |
||||
']': true, |
||||
'^': true, |
||||
'_': true, |
||||
'`': true, |
||||
'a': true, |
||||
'b': true, |
||||
'c': true, |
||||
'd': true, |
||||
'e': true, |
||||
'f': true, |
||||
'g': true, |
||||
'h': true, |
||||
'i': true, |
||||
'j': true, |
||||
'k': true, |
||||
'l': true, |
||||
'm': true, |
||||
'n': true, |
||||
'o': true, |
||||
'p': true, |
||||
'q': true, |
||||
'r': true, |
||||
's': true, |
||||
't': true, |
||||
'u': true, |
||||
'v': true, |
||||
'w': true, |
||||
'x': true, |
||||
'y': true, |
||||
'z': true, |
||||
'{': true, |
||||
'|': true, |
||||
'}': true, |
||||
'~': true, |
||||
'\u007f': true, |
||||
} |
Loading…
Reference in new issue