Hacker News new | ask | show | jobs
by _Marak_ 2928 days ago
Would you be able to elaborate on this?

Why is doing "in-line" signatures a worse design or a source of vulnerabilities? Are there any benefits for providing an in-line signature?

Any examples or additional information would be appreciated. Trying to better understand the issue at hand.

2 comments

You have to completely parse the message to extract the signature and then re-serialize the message before you're able to validate the message. Consider a situation where you have a defect in your parser:

- in-line signature: you're applying your parser and serializer to the untrusted body of the message, and then verifying the signature. If this is a malicious payload, you've just run it through your parser and serialzer.

- out-of-message signature: you have the full signature and can verify the message without running a potentially-malicious message through anything other than your signature-verification code.

Option1: json.inlineSig: '{ "a": 1, "b": 2, "signature": "ff1341234..." }'

Option2: json.outOfBandSig: '?????'

Option2: json.signature: 'File=json.outOfBandSig; Signature=ff12341234...'

Basically if you try and do option #1 you actually need to parse the content, and THEN find out it's untrusted (which means you need to _execute_ your parser on the potentially unknown / hostile bytes), and then pretend you never processed them in the first place (discard) unknown / hostile bytes.

If you do option #2 then you blindly process the bytes with the signature algorithm, verify they are trusted and THEN run your parser on bytes of a signed / known origin.

Compare:

signedParseInlineSig( '{ "a": 1, "signature": "<<INVALID>>" }' );

signedParseOutOfBandSig( '{ "a": 1 }', "<<INVALID>>" );

...with #1 you have to run isValid( input, JSON.parse(input).signature )

...with #2 you run isValid( input, signature ) && JSON.parse( input )

> Basically if you try and do option #1 you actually need to parse the content, and THEN find out it's untrusted (which means you need to _execute_ your parser on the potentially unknown / hostile bytes), and then pretend you never processed them in the first place (discard) unknown / hostile bytes.

And you need to remove the signature and reassemble the modified data structure back to bytes in EXACTLY the same way as the signer did. This is more work (for larger data structures) and way harder to get right.

Re-normalization of the message also has some other issues, e.g. you need to make sure that you are parsing and processing the re-assembled version (what the signature was checked against), not the message you received; otherwise your signature might be completely useless (think about an attacker inserting duplicate keys: the re-normalization might remove them, but your parser might normally not. Signature validates, but you're not processing what was signed! Oops.)

If you do this the best case scenario is that it kinda seems to work, and if you're lucky it's even secure, but it actually doesn't work or silently stops working for some messages after you update a parser somewhere in the system, because suddenly they disagree about some edge case, and your system breaks.