-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding/json: parser ignores the case of member names #14750
Comments
Playgroud link: http://play.golang.org/p/9j0ome9HqK @rsc, @adg, thoughts? This surprised me. I thought we only did the case insensitive thing when there was no struct tag. But from the ietf link above:
Related to "differently by different implementations", we permit JSON keys twice: http://play.golang.org/p/lPgEj1T6Zk (two "alg"). That probably differs between implementations in either its output or whether it's even successful. |
This has been the behavior at least as far back as Go 1.2 (I can't run
I understand there are security implications if JSON is used in security In any event it's too late to change the defaults. If we want to support |
UseStrictNames SGTM. |
The other issues are unrelated and shouldn't be mixed in here. For one
thing, we were talking about a decoding problem and #14749 is an encoding
problem.
|
UseStrictNames does look like a decent way to add case-sensitive decoding support in a backward compatible way. However, while that would make case-sensitive decodes possible, it wouldn't help make this safer mode common or the default. How about also defining a "strict" field tag option (c.f. "omitempty")? That should allow types to be safely used via newDecoder, or Unmarshall, or when the decoding is within a library. You can define the safety in the type, without finding every place it might be decoded. |
Shall I send a UseStrictNames CL? Should that apply strict names across the board, whether or not the user supplied a struct tag?
So that would only match exactly "Bar" and "baz". |
@cespare If it's simple, then yes sure. But after a thought on #15314 I wonder if maybe the UseStrictNames method is the wrong approach and instead it should be a tag attribute on the field. Then it can be enforced by the author of the struct instead of the author of the unmarshal call. Specifically, something like |
Would it get super repetitive if the person had to set it on every tag name? |
I think the CL is interesting, but it would, from my perspective, be even more useful to explicitly define an option. It's useful to be able to set that a case-insensitive match be treated as an unknown field. As a comment on #14750 (comment): I would vote for allowing case-sensitive matching as a decoder option enabled through a method call. ( I want to advocate for this solution not because it's a better solution, but because it's in line with the current design for The Some notes:
|
PS! The Encoder/Decoder interfaces defined in #12001 (old issue) could serve as a way of passing along decoder option. Perhaps that problem can be discussed there, although the motivation here is different. |
@rsc this issue seems to have died down and gone off-topic. Would it be appropriate to reboot this as a proposal for |
The wording of the first half line is some misleading IMHO. |
Just learned about this bahavior and this screams unintended bugs (no matter how much documentation). I always assumed that explicit struct tags take precedence over field names but they seem to just be ignore if there i field that matched. |
This breaks binance API parsing (see https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-ticker-streams) |
@krigga a different workaround wouldn't be to declare all possible attributes cases, even those not required by the application? For example, considering Binance's ticker payload, even if you only wanted to parse the "a" atribute, it seems to me that you could avoid the mismatching with the "A" field by declaring both on your target structure and simply ignoring the unwanted value https://go.dev/play/p/1_71Bw5FBJz. Of course, this is just a workaround for the issue. One shouldn't be required to parse unwanted atributes for the sole purpose of avoiding this behavior. On this same snippet, removing any of the struct fields (by commenting line 14 or 15) leaves the script susceptible to the mentioned awkward behavior, by parsing "a" into an atribute with an "A" field tag. |
This fork deals with the issue and implements the original proposed change I believe; https://github.com/james-d-elliott/go-json It's a 1:1 fork of go1.19.3 other than the additional method and usage of said method. If the original proposal ever gets traction and is accepted you're welcome to ping me and/or just use the code as-is/modified with/without crediting me. |
Hi all, we kicked off a discussion for a possible "encoding/json/v2" package that addresses the spirit of this proposal. In v2, we propose that For flexibility, the v2 prototype provides the ability to alter this behavior with:
|
Hi, we stumbled upon this issue at Trail of Bits during one of our security assessments. We found a critical vulnerability due to how two different parsers treated similar JSON keys with matching text but differing capitalization - one of which was a Go program. A bit off-topic, but this is also not the first time that the lack of specification on how to treat duplicate JSON keys caused a critical vuln, as per Parsing JSON is a Minefield 💣:
Anyway, I am writing here to encourage you to fix this issue - and at least request that this feature be documented better. I’m requesting this because the latest - Go 1.23 - documentation for
The doc says it "prefers an exact key match"; however, the [...]
# we always end up with "last" value
deserialize([]byte(`{"someName": "first", "SOMEname": "last"}`))
deserialize([]byte(`{"SOMEname": "first", "someName": "last"}`)) Now, it seems that different solutions were suggested here such as:
Having written all of this, I still believe we could at least improve the documentation in the current implementation to make this clear once and for all. |
Making the documentation more clear sounds good to me. At this point, I don't think we can change the v1 behavior. The v2 package will be the path forward for fixing this as we're aware that this is a potential security vulnerability. For those interested, here's an explanation how duplicate names (and case-insensitive names by extension) can be exploited: https://youtu.be/avilmOcHKHE?feature=shared&t=1011 |
@dsnet: What is your opinion today on https://go.dev/cl/221117 ? |
Yes, if we're not going to change the behavior in v1, I'd also document it. I'm still okay with my wording from four years ago, but happy to get another review. |
5.3
amd64,windows
Read this: https://mailarchive.ietf.org/arch/msg/json/Ju-bwuRv-bq9IuOGzwqlV3aU9XE
...
...
The text was updated successfully, but these errors were encountered: