aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2025-06-30 22:17:41 -0700
committerGopher Robot <gobot@golang.org>2025-07-14 07:58:11 -0700
commitc6556b8eb3444b6d5473762ed1082039db7e03b5 (patch)
tree243f19e74f46a96c16df83d66d5c7e6632ed4fbc /src
parent6ebb5f56d9ed35588970ce69cbad63508403bb8d (diff)
downloadgo-c6556b8eb3444b6d5473762ed1082039db7e03b5.tar.xz
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 <joetsai@digital-static.net> Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/encoding/json/jsontext/doc.go4
-rw-r--r--src/encoding/json/jsontext/options.go1
-rw-r--r--src/encoding/json/v2/doc.go94
-rw-r--r--src/encoding/json/v2_encode.go8
4 files changed, 107 insertions, 0 deletions
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 (