Airtable / airtable.js

Airtable javascript client
MIT License
1.98k stars 403 forks source link

How do I escape or parameterize user input in filterByFormula? #271

Open JoshCheek opened 3 years ago

JoshCheek commented 3 years ago

I want to search for some records based on some user input. The way to do that seems to be filterByFormula. But I cannot find any examples of how to either escape my user's input or how to pass that input in parameters that I can refer to from the formula.

I've checked the code for this package and 2 Ruby packages, one also written by Airtable, and it seems to be ignored in all of these. They all just accept a string for the value, and do not tell you how to escape inputs in that value. This feels like a really obvious security vulnerability to me, mechanically it's very similar to SQL injection.

For example, if I had a query like this:

`OR({Name} = "${Name}", {Email} = "${email}")`

A user could fill in the form, setting Name to Josh Cheek and email to josh@example.com", ""=", which would cause the query to become OR({Name} = "Josh Cheek", {Email} = "josh@example.com", ""=""), calling the OR function with 3 expressions instead of the intended 2, and in this case, constructing an input that causes the filter to match every single record.

In this example, the user is malicious, but it could also just be that the user's input is complex and happens to look like query structure. So, how do I either escape the input so that data doesn't get confused for structure, or else pass the inputs in a list of parameters that I can refer to from the formula, like PostgreSQL's $1, $2, $3, etc?

JoshCheek commented 3 years ago

After thinking about how it probably works, and looking at some of the examples in the docs I'm wondering if to escape it, maybe all we need to do is this, which will add a backslash before any existing backslash or quote:

const escape = input => input.replace(/[\\"]/g, c => `\\${c}`)

It looks promising based on this example:

const escape   = input => input.replace(/[\\"]/g, c => `\\${c}`)
const username = 'C:\\Users\\Josh'
const email    = 'josh@example.com", ""="'
const formula  = `OR({Username} = "${escape(username)}", {Email} = "${escape(email)}")`
console.log(formula) // prints: OR({Username} = "C:\\Users\\Josh", {Email} = "josh@example.com\", \"\"=\"")

Can anyone confirm this? And is the formula parser code available anywhere so I can verify I'm not missing any other cases?

JoshCheek commented 3 years ago

And still no one cares. Who cares about security? No one. 🤷 How many apps that use the API have injection vulnerabilities? Probably like half of them. And no one talks about it, and no one cares. Until, you know, someone's airtable base gets stolen and the company gets ruined or ransomed, all because every single example I've ever seen says to interpolate data into the API queries.

At least I'm not the lone voice anymore, someone else asked about it: https://community.airtable.com/t/escaping-of-data-in-formulas-for-api-calls/42882/2 aaaaaaaand in the responses, someone told them to just interpolate it 🤦