From: Joe Tsai Date: Tue, 1 Jul 2025 05:17:41 +0000 (-0700) Subject: encoding/json/v2: add security section to doc X-Git-Tag: go1.25rc3~5^2~28 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c6556b8eb3;p=gostls13.git encoding/json/v2: add security section to doc This follows up CL 684315 with an expanded section in the v2 doc. Updates #14750 Updates #71845 Change-Id: I1ffa97e030f5f2b709e8142028e3c8e0e38b80ce Reviewed-on: https://go-review.googlesource.com/c/go/+/685195 Auto-Submit: Joseph Tsai Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- diff --git a/src/encoding/json/jsontext/doc.go b/src/encoding/json/jsontext/doc.go index 8e4bced015..d890692686 100644 --- a/src/encoding/json/jsontext/doc.go +++ b/src/encoding/json/jsontext/doc.go @@ -103,6 +103,10 @@ // RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it. // In particular, it makes specific choices about behavior that RFC 8259 // leaves as undefined in order to ensure greater interoperability. +// +// # Security Considerations +// +// See the "Security Considerations" section in [encoding/json/v2]. package jsontext // requireKeyedLiterals can be embedded in a struct to require keyed literals. diff --git a/src/encoding/json/jsontext/options.go b/src/encoding/json/jsontext/options.go index e07de21fcf..7eb4f9b9e0 100644 --- a/src/encoding/json/jsontext/options.go +++ b/src/encoding/json/jsontext/options.go @@ -271,6 +271,7 @@ func WithIndentPrefix(prefix string) Options { /* // TODO(https://go.dev/issue/56733): Implement WithByteLimit and WithDepthLimit. +// Remember to also update the "Security Considerations" section. // WithByteLimit sets a limit on the number of bytes of input or output bytes // that may be consumed or produced for each top-level JSON value. diff --git a/src/encoding/json/v2/doc.go b/src/encoding/json/v2/doc.go index 203139754c..8179f8ab17 100644 --- a/src/encoding/json/v2/doc.go +++ b/src/encoding/json/v2/doc.go @@ -166,6 +166,100 @@ // Marshaling or unmarshaling a non-empty struct // without any JSON representable fields results in a [SemanticError]. // Unexported fields must not have any `json` tags except for `json:"-"`. +// +// # Security Considerations +// +// JSON is frequently used as a data interchange format to communicate +// between different systems, possibly implemented in different languages. +// For interoperability and security reasons, it is important that +// all implementations agree upon the semantic meaning of the data. +// +// [For example, suppose we have two micro-services.] +// The first service is responsible for authenticating a JSON request, +// while the second service is responsible for executing the request +// (having assumed that the prior service authenticated the request). +// If an attacker were able to maliciously craft a JSON request such that +// both services believe that the same request is from different users, +// it could bypass the authenticator with valid credentials for one user, +// but maliciously perform an action on behalf of a different user. +// +// According to RFC 8259, there unfortunately exist many JSON texts +// that are syntactically valid but semantically ambiguous. +// For example, the standard does not define how to interpret duplicate +// names within an object. +// +// The v1 [encoding/json] and [encoding/json/v2] packages +// interpret some inputs in different ways. In particular: +// +// - The standard specifies that JSON must be encoded using UTF-8. +// By default, v1 replaces invalid bytes of UTF-8 in JSON strings +// with the Unicode replacement character, +// while v2 rejects inputs with invalid UTF-8. +// To change the default, specify the [jsontext.AllowInvalidUTF8] option. +// The replacement of invalid UTF-8 is a form of data corruption +// that alters the precise meaning of strings. +// +// - The standard does not specify a particular behavior when +// duplicate names are encountered within a JSON object, +// which means that different implementations may behave differently. +// By default, v1 allows for the presence of duplicate names, +// while v2 rejects duplicate names. +// To change the default, specify the [jsontext.AllowDuplicateNames] option. +// If allowed, object members are processed in the order they are observed, +// meaning that later values will replace or be merged into prior values, +// depending on the Go value type. +// +// - The standard defines a JSON object as an unordered collection of name/value pairs. +// While ordering can be observed through the underlying [jsontext] API, +// both v1 and v2 generally avoid exposing the ordering. +// No application should semantically depend on the order of object members. +// Allowing duplicate names is a vector through which ordering of members +// can accidentally be observed and depended upon. +// +// - The standard suggests that JSON object names are typically compared +// based on equality of the sequence of Unicode code points, +// which implies that comparing names is often case-sensitive. +// When unmarshaling a JSON object into a Go struct, +// by default, v1 uses a (loose) case-insensitive match on the name, +// while v2 uses a (strict) case-sensitive match on the name. +// To change the default, specify the [MatchCaseInsensitiveNames] option. +// The use of case-insensitive matching provides another vector through +// which duplicate names can occur. Allowing case-insensitive matching +// means that v1 or v2 might interpret JSON objects differently from most +// other JSON implementations (which typically use a case-sensitive match). +// +// - The standard does not specify a particular behavior when +// an unknown name in a JSON object is encountered. +// When unmarshaling a JSON object into a Go struct, by default +// both v1 and v2 ignore unknown names and their corresponding values. +// To change the default, specify the [RejectUnknownMembers] option. +// +// - The standard suggests that implementations may use a float64 +// to represent a JSON number. Consequently, large JSON integers +// may lose precision when stored as a floating-point type. +// Both v1 and v2 correctly preserve precision when marshaling and +// unmarshaling a concrete integer type. However, even if v1 and v2 +// preserve precision for concrete types, other JSON implementations +// may not be able to preserve precision for outputs produced by v1 or v2. +// The `string` tag option can be used to specify that an integer type +// is to be quoted within a JSON string to avoid loss of precision. +// Furthermore, v1 and v2 may still lose precision when unmarshaling +// into an any interface value, where unmarshal uses a float64 +// by default to represent a JSON number. +// To change the default, specify the [WithUnmarshalers] option +// with a custom unmarshaler that pre-populates the interface value +// with a concrete Go type that can preserve precision. +// +// RFC 8785 specifies a canonical form for any JSON text, +// which explicitly defines specific behaviors that RFC 8259 leaves undefined. +// In theory, if a text can successfully [jsontext.Value.Canonicalize] +// without changing the semantic meaning of the data, then it provides a +// greater degree of confidence that the data is more secure and interoperable. +// +// The v2 API generally chooses more secure defaults than v1, +// but care should still be taken with large integers or unknown members. +// +// [For example, suppose we have two micro-services.]: https://www.youtube.com/watch?v=avilmOcHKHE&t=1057s package json // requireKeyedLiterals can be embedded in a struct to require keyed literals. diff --git a/src/encoding/json/v2_encode.go b/src/encoding/json/v2_encode.go index cbb167dbd0..c2d620bcbb 100644 --- a/src/encoding/json/v2_encode.go +++ b/src/encoding/json/v2_encode.go @@ -10,6 +10,14 @@ // // See "JSON and Go" for an introduction to this package: // https://golang.org/doc/articles/json_and_go.html +// +// # Security Considerations +// +// See the "Security Considerations" section in [encoding/json/v2]. +// +// For historical reasons, the default behavior of v1 [encoding/json] +// unfortunately operates with less secure defaults. +// New usages of JSON in Go are encouraged to use [encoding/json/v2] instead. package json import (