0.1.5 • Published 3 years ago

private-request v0.1.5

Weekly downloads
4
License
ISC
Repository
-
Last release
3 years ago

A fetch wrapper that hampers traffic analysis, based on Signal's Expanding Signal GIF search article.

This README outlines the high-level ideas, see CONTRIBUTING.md for information about how to contribute to/build the project.

What's the idea here?

From Signal's article:[1]

If the Signal service were malicious, it could measure the amount of data being transmitted in order to discern something about the GIFs being retrieved from GIPHY.

The most common way to mitigate an attack like that is through the introduction of plaintext padding. Including a random amount of padding at the end of each GIF would make it more difficult for the Signal service to correlate the amount of data it sees being transmitted with a known GIF.

We can also abuse range requests to simulate padding on content we don't control.

This package uses range requests to split a request into segments with some padding.

What does this mean in practice?

Using range requests we can turn 1 request for a N₁-byte resource into M requests for N₂-bytes, where:

  1. N₁ ≥ N₂; and
  2. (M × N₂) ≥ N₁

(At the time of writing the diagram in the Signal article has inconsistent segment sizes, so there is a different example below.)

Example

Pretend there is a 9-byte resource we want to request (N₁), and we pick a segment size of 4 bytes (N₂).

Instead of making one 9-byte request, we can make three 4-byte requests:

The range requests for the three segments:

RequestRangeSegment size
1bytes=0-34 bytes
2bytes=4-74 bytes
3bytes=5-84 bytes

We have requested the 5th, 6th, and 7th bytes twice and can discard the redundant copy.

Larger segment sizes

This package will use segment sizes a lot larger than 4 bytes, picking the smallest segment size (N₂) from the following list such that N₁ ≥ N₂ holds:

𝑥Unit
10kibibytes
50kibibytes
100kibibytes
500kibibytes
1mebibyte

What is the benefit?

With this approach we turn a request for 9 bytes into a request for 12 bytes, and hide the size of the resource. This makes it more difficult for an intermediary (e.g. a malicious proxy server) to know: is the client requesting three unrelated 4-byte resources or one 12-byte resource? (To which the answer is neither. 😏)

This comes at the cost of multiple extra network calls and bytes on the wire—a steep cost in some scenarios.

Quick start

NOTE: this package requires a random number generator that will produce uniform numbers, preferably one which is cryptographically sound. One option is pure-random-number, which is available for both browsers and Node.

To install and use the package:

$ yarn add private-request pure-random-number
import pr from 'private-request';
import randomNumber from 'pure-random-number';

const rng = async (min, max) => randomNumber(min, max);
const fetch = pr({ rng });
// Use as you would `window.fetch`

Tests

To run the test suite locally:

$ yarn
$ yarn build:data
$ yarn start:server
$ yarn test

To run the e2e tests, visit localhost:8001 in a browser.

License

This repository is available under the ISC License. See LICENSE.md.

On CORS

The ability to perform range requests on the web requires the correct CORS headers.

Namely:

Remember that the following environments do not enforce CORS:

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

4 years ago

0.1.2

4 years ago

0.1.1

4 years ago