Side Channel Attacks
defuse:
Reports from ooni-probe are identified by a report id, which is used in a file path. Checking the report id by opening the file may create a side channel that would allow an attacker to extract existing report ids from the server. With the report id, the attacker could overwrite other, existing reports with their own data and possibly do other bad things.
Is this a problem? Are there other side channels that could be a problem?
Note: This is not part of the Least Authority audit.
hellais:
This is indeed an issue, as we do want to guarantee integrity of not finalised reports.
How would you suggest making such comparison in constant time?
A possible solution would be to make a list of all the files that are stored in the temporary directory, xor every item in the list with the specified report_id. Check if there is any item inside of the list that is 0.
Is there a better way to do this?
defuse:
@hellais I think the proposed solution would still leak some information when the file is actually opened. You might be able to get away with opening all the files, then only using the file descriptor from the one that matches the provided report_id, but that's very inefficient (and I'm not even sure if that would be safe).
A better approach might be to make it OK for the attacker to learn the report ID. To do this, add a "report key", so that you need the report_id and the report_key to be able to write a report. The report_id would be part of the filename (or database index if you ever use a database), and then inside the file would be a hash of the report_key, which is checked in constant time. Then if someone else gets the report_id, it doesn't matter so much since they can't tamper with it without knowing the report_key.
This could be done without changing the API too much. The report ID currently contains 50 alphanumeric characters, so you could use the first 25 as the new report ID, and the last 25 as the report key.
Beware side channels that would leak the timestamp and/or ASN of other reports, since they are part of the report id and filename too.
defuse:
Note: While it could be done without changing the API, I don't recommend it. It would not obvious to the client what they have to keep secret and what they don't. It would be better to explicitly give the client a "report_key", which, as the name implies, has to be kept secret.
defuse:
As @hellais and I discussed in real life, the attacker can only get past the XOR check if they already know the report ID.
However, the report ID, or information about the other report IDs, might still be leaked in some cases:
For example, the attacker might create 1000 new reports, obtaining 1000 report IDs, then can monitor how the response time for each of those IDs changes over time to learn things about the new report IDs (that they don't know) that were created during that time.
Another example: an attacker who can measure cache usage via unprivileged code running on the same physical system might be able to learn information about the report IDs used by actual users.
I doubt something like that would be exploitable in practice, but if we want to be perfectly side-channel free, we should consider those kinds of attacks.