Live data from Hacker News

How (not) to sign a JSON object (2019)

latacora.com

11–20 of 45 posts

Re: How (not) to sign a JSON object (2019)

#11
post #4

Not sure if I'm just misunderstanding the article or not, but it feels like an overengineered solution, reminescent of SAML's replacement instructions (just a hardcoded and admittedly way better option --- but still in a similar vein of "text replacement hacks"). I know it's not the most elegant thing ever, but if it needs to be JSON at the post-signing level, why not just something like `["75cj8hgmRg+v8AQq3OvTDaf8pE…

Json encoded as a string is cursed, no one should do that and stop suggesting it. Base64 is fine or even ascii85

base64 is often even larger than an escaped JSON string. and not human-readable at all.

I'll take stringified json-in-json 90% of the time, thanks. if you're using JSON you're already choosing an inefficient, human-oriented language anyway, a small bit more overhead doesn't hurt.

(obviously neither of these are good options, just defer your parsing so you retain the exact byte sequences while checking, and then parse the substring. you shouldn't be parsing before checking anyway. but when you can't trust people to do that...)

Re: How (not) to sign a JSON object (2019)

#12
post #7

Not sure if I'm just misunderstanding the article or not, but it feels like an overengineered solution, reminescent of SAML's replacement instructions (just a hardcoded and admittedly way better option --- but still in a similar vein of "text replacement hacks"). I know it's not the most elegant thing ever, but if it needs to be JSON at the post-signing level, why not just something like `["75cj8hgmRg+v8AQq3OvTDaf8pE…

> in other words, encode the JSON being signed as a string. This would then ensure that, even if the "outer" JSON is parsed and re-encoded, the string is unmodified. It'll even survive weird parsing and re-encoding, which the regex replacement option might not (unless it's tolerant of whitespace changes). Would it be guaranteed to survive even standard parsing? It wouldn’t surprise me at all, for example, if there ar…

Presumably when receiving the object, you'd first unescape the string (which should yield a unique output unless you have big parser bugs), check the UTF-8 bytes of the unescaped string against the signature, and only then decode the unescaped string as the inner JSON object. It shouldn't matter how exactly the string is escaped, as long as it can be unescaped successfully.

Re: How (not) to sign a JSON object (2019)

#13

Not sure if I'm just misunderstanding the article or not, but it feels like an overengineered solution, reminescent of SAML's replacement instructions (just a hardcoded and admittedly way better option --- but still in a similar vein of "text replacement hacks"). I know it's not the most elegant thing ever, but if it needs to be JSON at the post-signing level, why not just something like `["75cj8hgmRg+v8AQq3OvTDaf8pE…

You can and this will be simple and reliable.. but that's solving the different (and easier) problem that the post. In the post, author wants to have still have parsable JSON _and_ a signature. Think middleware which can check signature, but cannot alter the contents, followed by backend expecting nice JSON. Or a logging middleware which looks at individual fields. Or a load balancer which checks the "user" and "project" fields. Or a WAF checking for right fields. In other words:

> Anyone who cares about validating the signature can, and anyone who cares that the JSON object has a particular structure doesn’t break (because the blob is still JSON and it still has the data it’s supposed to have in all the familiar places).

As author mentions, you can compromise by having "hmac", "json" and "user" (for routing purposes only), but this will increase overall size. This is approach 2 in the blog.

Re: How (not) to sign a JSON object (2019)

#14
post #4

Not sure if I'm just misunderstanding the article or not, but it feels like an overengineered solution, reminescent of SAML's replacement instructions (just a hardcoded and admittedly way better option --- but still in a similar vein of "text replacement hacks"). I know it's not the most elegant thing ever, but if it needs to be JSON at the post-signing level, why not just something like `["75cj8hgmRg+v8AQq3OvTDaf8pE…

Json encoded as a string is cursed, no one should do that and stop suggesting it. Base64 is fine or even ascii85

The comment you replied to was posted in good faith AFAICT. Your “stop suggesting it” is unnecessarily antagonistic.

Re: How (not) to sign a JSON object (2019)

#15
post #10
post #9

Earlier quoted context omitted.

I saw from the main page that you are aware of COSE (RFC 8152), with it's super similar name, but I didn't see anything in https://github.com/Cyphrme/CozeX/blob/master/coze_vs.md comparing it or CBOR. Is the improvement COZE has over COSE that the body is default human readable, whereas COSE it's in some machine format that needs a reader util?

We picked the name Coze as a play on words on JOSE ("Cypher JOSE", when Jose is typically pronounced in Spanish, "ho-zay". The English word coze meaning a friendly chat was too perfect for the name of a messaging specification). I somewhat regret not using the three letter "coz". Cose also picked its name while thinking of JOSE. Cose is binary oriented, and attempts to be as similar to JOSE as possible. Coze is a fir…

Thanks for explaining the background of that.

I agree that human readability can make things somewhat easier. The part about a binary format for the signatures confuses me a little - the signatures are going to be big no matter what. If you care about minimizing size would it make sense to just find a more efficient way to encode the signatures rather than change the entire message format?

Re: How (not) to sign a JSON object (2019)

#16
post #11
post #4

Earlier quoted context omitted.

Json encoded as a string is cursed, no one should do that and stop suggesting it. Base64 is fine or even ascii85

base64 is often even larger than an escaped JSON string. and not human-readable at all. I'll take stringified json-in-json 90% of the time, thanks. if you're using JSON you're already choosing an inefficient, human-oriented language anyway, a small bit more overhead doesn't hurt. (obviously neither of these are good options, just defer your parsing so you retain the exact byte sequences while checking, and then parse…

[deleted]

Re: How (not) to sign a JSON object (2019)

#17
I have a feeling that idea 2 is a recipe for disaster:

> Add the tag and the exact string you signed to the object, validate the signature and then validate that the JSON object is the same as the one you got.

In cryptographic practice, redundant information usually spells disaster, because inevitably, someone will use the copy that wasn't verified.

But let's dig into it. If I understand this correctly, the suggestion is to have something like this:

    {
        "object": "with",
        "some": "properties",

        "signatureInfo": {
            "signedString": "{\"object\":\"with\",\"some\":\"properties\"}",
            "signature": "... base64-encoded-signature ..."
        }
    }
It's mentioned that "the downside is your messages are about twice the size that they need to be". In my opinion, this scheme is pointless. To verify "the JSON object is the same as the one you got", you have to do what?

1. Parse the outer object as JSON, extract and remove signatureInfo.

2. Verify the signature.

3. Parse the signedString as JSON.

4. Verify that the object you got in step 1 equal to object you got in step 3 using a some kind of deep equality.

First of all, this is error prone, and as underspecified as JSON is, there are potential exploits if the comparison isn't done carefully. But even worse, if you think about it, the outer JSON is entirely useless, since you need to parse the inner JSON anyway -- so why not just use it directly?

It seems to me that this suggestion is strictly worse than just sending the inner part:

    {
        "signedString": "{\"object\":\"with\",\"some\":\"properties\"}",
        "signature": "... base64-encoded-signature ..."
    }
Yes, it's no longer "in-band", but I don't think it was really in-band before, it was just out-of-band with an outer layer of redundant information.

Re: How (not) to sign a JSON object (2019)

#18
post #15
post #10

Earlier quoted context omitted.

We picked the name Coze as a play on words on JOSE ("Cypher JOSE", when Jose is typically pronounced in Spanish, "ho-zay". The English word coze meaning a friendly chat was too perfect for the name of a messaging specification). I somewhat regret not using the three letter "coz". Cose also picked its name while thinking of JOSE. Cose is binary oriented, and attempts to be as similar to JOSE as possible. Coze is a fir…

Thanks for explaining the background of that. I agree that human readability can make things somewhat easier. The part about a binary format for the signatures confuses me a little - the signatures are going to be big no matter what. If you care about minimizing size would it make sense to just find a more efficient way to encode the signatures rather than change the entire message format?

Coze uses base64 encoding for binary values such as `tmb` and `sig`. `tmb` isn't a problem since digests are designed to be short, but signatures for some primitive might be very large.

When compared to encoding a value directly in binary, base64 has about a 25% overhead (6 bits /8 bits, 3/4). As far as the concern about using better encoding, base64 is just about as good as it gets while being maximally compatible. If using base 128 (7 bit ASCII), there's too many incompatible special characters for a human readable format. The full 8/8 bits, extended ASCII, isn't generally possible as systems use UTF-8 which begins using multiple bytes. (I've done a lot of work in this area, including a patent on base conversion. See also convert.zamicol.com) An advantage of a binary format is that there is minimal encoding overhead for binary values (escaping/padding is typically the only overhead, so usually around 99% efficient compared to base64's 75%.)

This isn't too much of a concern when signatures are small as encoding inefficiency is small compared to the payload's overall size, but if signatures are in the kilobytes or even megabytes, that extra 25% becomes meaningful for some hyper-efficient applications, like high cost blockchains. Our thought is using post quantum is already much more massive than existing elliptic curve, so any future applications of post quantum are going to have to deal with much larger signatures anyways. The signatures can also be stored on disk using binary or compressed which also makes it not a concern.

Re: How (not) to sign a JSON object (2019)

#19
post #6

We addressed these concerns while developing Coze, a cryptographic JSON messaging specification. The specification details how we chose to address these concerns. https://github.com/Cyphrme/Coze

Very cool! It shares its name with "COSE" (RFC 8152), a signing scheme for CBOR objects :)
Post reply on HN