Why API responses should be signed


I'm going to start this discussion with the why and then move on to the how. Let's begin with a couple of user stories.

As the recipient of some data, I want to verify that it hasn't been tampered with.

and

As the recipient of some data, I want to verify who originally published it.

Here's why I think this is important. We are in an era of fake news. A screenshot can be easily altered. A webpage is trivial to edit. But data should be provably true.

Recently, a prominent person's private Twitter messages were leaked. It was presented as a series of JSON files ostensibly directly from the API. But, of course, there was no way to prove the data-dump didn't contain misinformation.

If I call https://api.example.com/?id=123 myself, then I can be reasonably sure that the data has come from the server unaltered.

But what if someone emails me a JSON file? Or someone re-hosts an XML dump? Or a hacker claims to have uncovered proof of...?

As data-journalism gathers pace, it's vital to be able to see whether data is authentic.

Suppose you see a news site claiming that your favourite sports star endorses the opposing team. They have an image of a tweet. But you wouldn't trust an image of a website (I hope) without a checking a live link. Right?

Fake tweet showing the Victoria Government announcing I am King of Australia.

But in the data world, we get no such assurances.

Here's data from a Tweet I've just faked:

{
  "created_at": "Wed Oct 10 20:19:24 +0000 2018",
  "id": 105011862119892123,
  "text": "Terence Eden is now officially the King of Australia",
  "user": {
    "id": 6253282,
    "id_str": "6253282",
    "name": "Australian Government",
    "screen_name": "AusGovOfficia1",

I've just made that up. But you've got no way to prove that it did not come from Twitter. Perhaps it was a real Tweet which was subsequently deleted?

Where this matters

Do you rely on data for your job? If someone gives you a scrap of data claiming to be from a website, how can you prove it is authentic?

Perhaps a Police API tells you what the crime rate is, or a betting API tells you what the odds are, or a news API tells you who was convicted of a crime. Or a source leaks information from a social network. How can you prove that the data is authentic and unaltered? Or someone else could present false data as coming from a trusted source. Or a trusted source could publish fake data and later claim they didn't.

Here's the end result that I want.

  • Given a piece of data,
  • Prove that where it came from and,
  • Prove that it hasn't been altered.

How to do it

This is where I get stumped. I can clearly see the need for this. Disinformation is an attack on civilisation. But I can't see how to do it in a seamless and easy to understand way.

There have been lots of proposals for how to do this.

I think it boils down to three distinct design choices.

  1. Keep the signature and the message separate.
  2. Include the signature in the message.
  3. Only sign part of the message.

Separation of Powers

The first is conceptually easiest.

  • The API call example.com/?id=123 returns some JSON containing the data requested.
  • The API call example.com/?id=123&signed=true returns the signature only.

It relies on a few assumptions. Mostly that a GET operation is Immutable in terms of what it returns. That is, the data returned from a query is always the same.

It reduces complexity for the server and client. If the client doesn't care about verification, the server doesn't have to calculate it.

It might be complicated to store the information. You would need to keep response.json and response.signed.json as separate files.

It might be fragile. If a single bit or byte of the data is altered - say tabs get converted to spaces - then the signature could become invalid.

If you want someone to verify an API response, they need two separate files and need to load them in the right order into any verification system. Again, not an impossible task, but might make things more complicated than necessary.

Inclusivity

Does the set of all sets include itself? This isn't just a philosophical problem. If a signature is included in a response, does the signing process have to take account of the signature?

The usual way around this is to encode the result first. So, imagine your API response was BASE64 encoded and then signed. It might look like this:

{
   "response": "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D...",
   "signature": "0f60066673e0de...."
}

That keeps the document and signature together, but does have some disadvantages. It loses the human-readable nature of the response. It also means that your code has to BASE64 decode the response before interpreting it. Both of those are annoying for debuggers - but not critical issues.

Partial

What if we only sign the critical parts of the response, rather than all the metadata? This is perhaps the easiest to implement, but has some drawbacks.

{
  "created_at": "Wed Oct 10 20:19:24 +0000 2018",
  "id": 105011862119892123,
  "text": "Terence Eden is now officially the King of Australia",
  "text-sig": "0f60066673e0de....",
  ...

That is, only sign the text. Or perhaps text + ID. Or any useful subset of the API response. It's simple to parse for humans and computers. But the metadata might be a crucial part of the information we want to verify. Knowing the date something was published, for example, could be as important as the content itself.

Put it all on the blockchain!!!!!

No.

Well... OK. Maybe this is a use for a Merkle Tree or similar. If every API response has an ID, then a cryptographic hash could be appended to a public ledger. But that has all the disadvantages of the previous schemes without any real benefit.

Security is hard

The problem with all of the above approaches is that the API provider needs to safely and securely manage cryptographic keys. That's expensive and complicated. If an attacker got access to the keys, they could issue fake statements.

But, the good news is that the tech tech is here and it works. JOSE is a suite of specifications - including JSON Web Tokens - which are well used across the Internet. Mostly for signing OAuth logins.

So, can we use it?

Will anyone care?

I suppose this is the crucial question. Right now I can easily fake a screenshot and the majority of people won't even look to see if the information is true - no matter how incredible the claim is.

But we need to build a better foundation for the future. One where information brokers can say "I have proof that this exact data came from this specific website at this precise time."

We have to believe that truth and trust are important.


Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

36 thoughts on “Why API responses should be signed”

  1. said on twitter.com:

    Good read. Seeing signatures used more and more actually, I wonder from a tech point of view if that’s trust or easier to consume?

    Slack and Alexa both put the sig data in the API response headers so the entire body is signed, always going to be based on trust somewhere

    Reply | Reply to original comment on twitter.com
    1. George says:

      The requirement for the first case isn't idempotence. It might be that the request is idempotent in that it doesn't affect the resource, but the resource might still change over time! Good APIs might make guarantees about some URIs always referring to static resources, but certainly not all resources should be so.

      It's a hard problem. See also SAML: in principle every interesting fact is an assertion. Other more modern things in that space exist too.

      Reply
  2. said on twitter.com:

    I think that's the use case with public data or webhooks where you need verification to move forward.

    APIs with authorization it seems to be missing almost entirely - I think that has to catch up. I hope it does, makes my cynical and security focused nature less twitchy 😁

    Reply | Reply to original comment on twitter.com
  3. said on twitter.com:

    1a) What exactly does the signature tell you? + That the statement is correct? Mistakes happen. + That the provenance is correct? Leaks of sensitive data happen but this means that anyone with a copy can republish it with your signature intact. + That a process was followed? ...

    Reply | Reply to original comment on twitter.com
  4. said on twitter.com:

    Some of the clumsiness in deciding what specific byte stream to sign seems to come down to the use of JSON. BitTorrent solves that by using bencode: part of the protocol relies upon an arbitrary structure being round-trippable and hashable back to the same value.

    Reply | Reply to original comment on twitter.com
    1. says:

      Sort of. Although VC is now Verifiable Credentials. And not all API responses are credential-like.

      Reply
  5. says:

    Perhaps it was a real Tweet which was subsequently deleted?

    This is exactly why Twitter can’t (or at least probably shouldn’t) implement signed API responses. A nice property of Twitter as it stands is that, if you delete a post, it is no longer possible to prove that you ever posted it. Your best option would be to use something like the Wayback Machine, but even then you can’t prove it.

    If they signed their API responses, then suddenly deleting a post would become less effective. If you’d captured the signature, you could prove that the post did exist with that content. This isn’t necessarily desirable­ (see non-repudiation1). In fact, this is something that many secure communication systems are designed to make impossible (TCP, Axolotl (Signal Protocol), etc.).

    Whether Twitter should offer Delete functionality across the board is another discussion, but while they do, implementing signed API responses would hobble it.

    Reply
  6. says:

    Coincidentally I recently saw a heavily-commented-upon tweet which looked a bit unbelievable so I searched through the alleged OT's stream to find if it was actually posted by them. It wasn't. Two things arise from that though; firstly that in many ways it ceased to matter - it now had a life of its own and accuracy had ceased to be relevant - and secondly that there was no obvious way to correct everyone else's misunderstanding.
    The cartoon about "someone is wrong on the internet and I must tell them" might well be accurate (certainly is for me on occasion!) but there is little-to-nothing which can be done. I believe the similar situation applies with data as, unless the original source promulgates the security as an integral component of the data, it can be separated and lost far too easily.

    Reply
  7. John Bob says:

    Seems like the perfect use-case for HTTP headers (e.g., Slack does this).

    The header (e.g. something like X-Signature) would contain the signature for the request body. (Note that you have to format the JSON response exactly the same way for the signature to work – simple way would be “sorted keys, zero whitespace”)

    Reply

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">