Issue C. Receipts are Too Short #823

fpietrosanti opened this Issue Mar 3, 2014 · 17 comments


None yet

5 participants


The receipts that allow a whistleblower to access their submission are too short.

current receipt regexp: [0-9]{10}

remediation suggested:
To fix this problem, the default value of receipt_regexp should be changed so that receipts are
longer. Node administrators should be notified of the trade-off between plausible deniability (disguising the
receipts as phone numbers) and guessability. We suggest that the receipts have at least 80 bits of
entropy. A sane default value might be [0-9a-z]{16}.

@fpietrosanti fpietrosanti added this to the LeastAuthorityPentest milestone Mar 3, 2014

@defuse @zooko :

we think that changing the receipt format from [0-9]{10} to [0-9a-z]{16} will complicate the usability so much and having a long an alphanumeric receipt prevent the idea of the plausible deniability
at the base of the design.

what about keeping the current receipt format and adding a new additional user configurable password?
this idea comes also from a UX study that has been proposed in the last week. In fact an internet user get used to associate an username to a password.

this solution sounds acceptable?
system receipt: [0-9]{10}
user defined password (per receipt): [at least 8 chars long, at least one number, at least upper case letter, at least one lower case letter)


I suggest to strongly reduce the minimum password strength in order to have a valuable usability experience. With this new password based approach, we'll have all the protection of anti-bruteforcing features.
An attacker must:

  • Identify which is the submission identifier (10 digits)
  • Bypass the anti-bruteforcing feature
  • Do the attack before the submission expire and self-delete itself
  • Find the right password

So the question is: How "simple" could be the password, in order to leave the system highly usable?

defuse commented Mar 11, 2014

This issue may be more severe than we previously thought. If you consider an
attacker who is interested in accessing any one of the N Tips in a GlobaLeaks
deployment, the time it takes to do the attack is greatly reduced.

For example, if there are 100 Tips, and the attacker can guess receipts at
a rate of 1000 per second (consistent with an online attack), then they can
expect to find one of them in only 14 hours on average.

defuse commented Mar 11, 2014

Allowing the whistleblower to provide a password makes it easier for the
whistleblower to accidentally reveal their identity. For example, if the
whistleblower's password was derived from identifying information (their
birthday, address, name, etc), or if they re-use a password they used for
a different account, then the GlobaLeaks Node administrator can use it to
confirm the identify of the whistleblower.

Therefore we recommend either (1) Don't let the whistleblower provide
a password, choose it randomly for them, or (2) Warn them of this risk.


I think that we're over-complicating the solution, given the need to maintain a high level of usability, why don't just work on the issue of the brute forcing?

If we introduce a proof of work, hashcash based, anti bruteforcing system like per #799 we may aggressively slowdown any kind of bruteforcing attempt.

What do you think?


A complete concept to keep a single numeric receipt, fixing the security concern could be:

Receipt became 16 digits, divided in 4 x 4 digits.

The first two get used internally by the backend to represent an "identifier".

Any "identifier", after 5 failure within 1 hour, it's just disabled for 1 hour.
When an identifier is disabled due to 5 consecutive failure, the client is not told anything special if another attempt is done (don't tell if it's temporarily blocked or not).
That way:

  • in 1 day it's possible to do a maximum of 5*24 = 120 retry for a given identifier.
  • in 15 days (default time before the Tip expire, self deleting) = 1800 retry for a given identifier

With such an approach the attacker can't know if he found a valid identifier (for example with the purpose of DOSsing it to prevent whistleblower's access), so can't know if he have the chance to try to bruteforce within 15 days a maximum of 1800 attempt (over an 8 digits password space)

On top of that, we introduce a javascript based hashcash proof of work, just to further increase the cost to crawl the entire space.

I think that a solution like that could be rock-solid, still keeping very high level of usability?

vecna commented Mar 11, 2014

@fpietrosanti I like the approach, so internally we've to check that the first two quartet are UNIQUE, and the second quartet CAN collide. right ?

I decline the specification of timings for blocking and stuff. we can use the same logic of receiver anti bruteforce tech. why make something new ? the quartet are 0LOG-IN00-PASS-WORD ;)


@vecna we should try to keep everything numeric, as it's the only way to be highly usable, not ending up in the problem of pgpwordlist/securedrop codewords that have serious internationalization issue. The problem with the anti-brute force of receiver is that The attacker would understand which is the identifier (the first two quartet), enabling to do a specific DOS to keep that whistleblower out


yep i like this design also, as (4-4-4-4) digit sequences are so common in products et cetera.

defuse commented Mar 17, 2014

Splitting the receipt into two halves, which the attacker might be able to guess
independently, is worse than keeping the existing system and just increasing the

This is because with the receipt split in half, guessing attacks on each half
are feasible, so defense would rely on the lockout feature, and the lockout
feature itself creates DoS vulnerabilities and usability issues (How does the
whistleblower know their receipt is locked out and they are not typing it

Using 16-digit receipts (not split into two) is safe against uninhibited online
attacks. My calculations say it would take over 80 days of guessing at a million
guesses per second to find one of any 1000 existing Tips. This is also a smaller
change to the code, since it can be done by changing the default receipt regexp.


The "split in half" (16 digits) would be something that we would do only in "the backend" (8 digits for ID, 8 digits for password) but that's not known by the whistleblower.
Still it would enable us to rely on the lockout that's very strong because it enable to set an "hard-limit" on the amount of guesses possible per receipt, de-facto fixing any kind of brute forcing attempt.

Do we agree that's lockout is strong enough against brute-force attack? Maybe we can refine the lockout algorithm, making it exponentially grow up with the number of failed attempt, to further reduce the amount of possible guesses.

In this scenario a Dos doesn't seems much feasible. A DoS to be done, would require an attacker to learn the first 8 digits of the receipts. That means that the attacker already found already the second 8 digits (because from the end-user perspective it would be a unique 16 digits, represented in 4x4 digits string).

From the Whistleblower perspective, which is the value of telling him that a Receipt is locked?
He just need to know OK/NOT-OK. A locked receipt, would be a way for us to prevent the brute forcing attack, but it's a globaleaks internal security measure that does not involve the Whistleblower (nor the attacker) awareness of it.

That way globaleaks, when receiving those 16digits string, would just answer:

  • OK, giving access to the Tip
  • NOT OK, not giving access to the Tip

Neither the attacker, nor the whistleblower would be able to differentiate if:

  • Tip Exists or not
  • The "password is wrong" or not
  • The ID is locked out or not

I would strongly prefer to trying to find a method that enable us to use only digits from the end-user perspective, while keeping in place a very strong brute-force protection.

What do you think?

defuse commented Mar 26, 2014

I do not think it is reasonably possible to prevent an attacker from differentiating those things. You can make the interface not say what the reason is, but the timing of the response (side channel) will still reveal the true reason. It would be very hard to write it in a way that the response time doesn't leak the reason, so I recommend not relying on the reason not being leaked.

Assuming a side channel will leak the reason, then it is possible to learn the first 8 digits without learning the last 8 digits, and DoS becomes possible, and lockout is the only thing preventing the attacker from getting in.

Whereas if you just change the regexp to [0-9}{16} (or whatever), then even if there are 1000 Tips it would take a year of guessing at 10,000 guesses per second to find one of them, so no lockout system would be needed. However, if DoS is not a problem, then the split-receipt lockout system does provide stronger guessing protection.

@evilaliv3 evilaliv3 added a commit to globaleaks/GLBackend-outdated that referenced this issue Apr 8, 2014
@evilaliv3 evilaliv3 addressed issue globaleaks/GlobaLeaks#823 8d69230
@evilaliv3 evilaliv3 added a commit to globaleaks/GLClient-outdated that referenced this issue Apr 8, 2014
@evilaliv3 evilaliv3 addressed issue globaleaks/GlobaLeaks#823 8dbc9a4
@evilaliv3 evilaliv3 added a commit to globaleaks/GLBackend-outdated that referenced this issue Apr 8, 2014
@evilaliv3 evilaliv3 addressed issue globaleaks/GlobaLeaks#823 72579bb

Allright, i've implemented a receipt with the format of [0-9}{16}.

the receipt is composed by two parts: receipt1 and receipt2
the backend keeps the two secret hashed: receipt1 is hashed with node.receipt_salt, receipt2 is hashed with a new wbtip.receipt_salt; by doing this an attacker that steal the stored recepts parts has no one of the two parts in cleartext.

in this proposal the receipt format is no more configurable (16 charset long), but configurable is the charset (e.g. [0-9a-zA-Z]).

the current authentication is compatible with the old receipt thanks to and if else condition that will be removed in future release. also in future release it would be possibile to implement a new design of the UI with an input form of XXXX-XXXX-XXXX-XXX but let's postpone this for the moment.

@vecna / @hellais / @fpietrosanti


@vecna @hellais : just for clarification, receipt1 will act in future as username and receipt2 as password (transparently to the user and on the backend side only). i've not added a Whistleblower user type to not have to change a lot of code and due to the fact that the whistleblower is always associated to a whistleblower tip

hellais commented Apr 11, 2014

I think splitting the receipt into two parts for the purpose of bruteforce prevention is not a good idea. It would make the task of bruteforcing the receipt easier than without the prevention technique. The attacker has a way, based on timing, to determine if they have guessed the first half or not.
This means that it would reduce the security of the receipt from 10 to 8.

Therefore I would suggest that we simply switch to using by default a receipt of 16 numerical chars.

@defuse do you think this is a reasonable approach in order to resolve the issues raised in the pen test?

Also it should be noted that in the context of receipts using a different salt for every receipt is not that much important. This is because if an attacker is capable of conducting an offline attack on the salted receipts they probably already have access to the whole database therefore there is nothing more that they can gain by bruteforcing it (they have the submissions and they have the receipts and their salts).

@hellais hellais added a commit to globaleaks/GLBackend-outdated that referenced this issue Apr 11, 2014
@hellais hellais use by default receipt of 16 numbers fixing globaleaks/GlobaLeaks#823 4ce5efd
defuse commented Apr 11, 2014

@hellais Yes, I agree.

@hellais hellais added a commit to globaleaks/GLBackend-outdated that referenced this issue Apr 11, 2014
@hellais hellais use by default receipt of 16 numbers fixing globaleaks/GlobaLeaks#823 6c9e48b
vecna commented Apr 15, 2014

Now they are forced to be always 16 bytes lenght. The reverse regexp still exists (default [0-9]{16}, optionally someone can use [A-Z]{8}[0-9]{8} or whatever they like )

@vecna vecna closed this Apr 15, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment