link-lock icon indicating copy to clipboard operation
link-lock copied to clipboard

Is there protection against brute force attacks?

Open cktang88 opened this issue 4 years ago • 10 comments

For example, a potential attacker could potentially keep on guessing a password many times via brute-force until the link unlocks.

cktang88 avatar May 20 '20 21:05 cktang88

Thanks for taking a look at the project! Theoretically, that is absolutely possible! Unfortunately, I am not aware of anything I can realistically do to protect against it. For example, given that all encryption and decryption is done client-side, I could not effectively perform rate-limiting.

Out of curiosity, I wrote a quick brute-force tool to try it out. While I know that nobody would actually ever brute-force anything too seriously in their browser, I coded up a web-based brute-forcer that will attempt to decrypt locked URLs by trying all combinations of characters in a user-submitted charset. I made a browser-based implementation simply because I could directly import the APIs I'd already written for the main project.

~~You can try my brute-forcer here. The code for it is here if you would like to modify it.~~ I have included a link to my brute-force application below. In practice, using this very naive implementation of brute force, it turns out that even relatively short passwords with limited character sets take a very long time to crack! For me it tests about 22 passwords per second.

In the meantime, I will leave this issue open in case others have ideas for how to protect against this.

jstrieb avatar May 21 '20 09:05 jstrieb

In the spirit of openly discussing this issue, I have added the code to brute force locked links directly to the main repository. Users can attempt a brute force in their browser here:

https://jstrieb.github.io/link-lock/bruteforce/

jstrieb avatar May 22 '20 04:05 jstrieb

A solution is to use scrypt or bcrypt instead of directly AES.

So you can provide complexity parameters that will make very hard for an attacker to brute force the password.

yogsototh avatar Aug 08 '20 12:08 yogsototh

A solution is to use scrypt or bcrypt instead of directly AES.

Since a user with the password must be able to recover the original URL, I need the encryption to be symmetric, and cannot use a hashing algorithm for this. Thus, I wouldn't actually be able to replace AES with bcrypt or scrypt. I could potentially use those hash functions in place of SHA-256 for secure key derivation, but unfortunately neither algorithm seems to be available in the SubtleCrypto API.

jstrieb avatar Aug 08 '20 14:08 jstrieb

As a fun project while learning Go, I wrote a cross-platform, command-line application to brute force Link Lock URLs. It parallelizes on as many CPU cores as possible. Find it here: https://github.com/jstrieb/bruteforce-link-lock

Interestingly, while profiling this code, I discovered that (perhaps unsurprisingly) the bottleneck for each attempt is the 100,000 iterations of SHA256 used for PBKDF2 key derivation. What did surprise me is that the Go code's rate of attempts per second per thread does not seem to be significantly better than the browser (both between 15 and 20 password attempts per second), so the only benefit of this new code over the browser-based brute force tool is parallelizing across CPU cores. Turns out the SubtleCrypto API is pretty fast!

jstrieb avatar Apr 29 '21 22:04 jstrieb

Not seeing that work right the - I have roughly 52 threads and its only running on one.

PrinceOfParallax avatar Mar 27 '22 00:03 PrinceOfParallax

hey @jstrieb i have a question about where the password is being stored in the client side?(is it inside the url itself)?

cool-dev-guy avatar Sep 08 '23 07:09 cool-dev-guy

hey @jstrieb i have a question about where the password is being stored in the client side?(is it inside the url itself)?

Hi @cool-dev-guy! The password is not stored at all. Only encrypted data is stored. And all of the encrypted data is stored in the URL.

To give a concrete example, here is the structure extracted from one of the example URLs in the README.

jacob@jacob:~$ echo "https://jstrieb.github.io/link-lock/#eyJ2IjoiMC4wLjEiLCJlIjoiZEx3Yi9CNitlK0ZjM1B3ZURrbUY2NjdQWFlIV1dsS3dpclhvZmkvRXBFTXU0ZERlVkJuSmUrN1loS2JxQ3RrPSIsImgiOiIxICsgMSA9ID8iLCJpIjoiRDJYd1MyK1EzaHpuUDV1NyJ9" \ 
  | sed 's/.*#\(.*\)/\1/g' \
  | base64 -d - \
  | jq
{
  "v": "0.0.1",
  "e": "dLwb/B6+e+Fc3PweDkmF667PXYHWWlKwirXofi/EpEMu4dDeVBnJe+7YhKbqCtk=",
  "h": "1 + 1 = ?",
  "i": "D2XwS2+Q3hznP5u7"
}

Within this extracted JSON structure:

  • v is the API version
  • e is the base64-encoded, encrypted bytes
  • h is the (optional) password hint
  • i is the Initialization Vector (IV) for AES-GCM

The password itself is not stored in here, but all of the encrypted data is entirely in the URL. If we go one step further and try to inspect the encrypted data, we'll see that it doesn't have any structure itself, and is just gibberish bytes.

jacob@jacob:~$ echo "https://jstrieb.github.io/link-lock/#eyJ2IjoiMC4wLjEiLCJlIjoiZEx3Yi9CNitlK0ZjM1B3ZURrbUY2NjdQWFlIV1dsS3dpclhvZmkvRXBFTXU0ZERlVkJuSmUrN1loS2JxQ3RrPSIsImgiOiIxICsgMSA9ID8iLCJpIjoiRDJYd1MyK1EzaHpuUDV1NyJ9" \
  | sed 's/.*#\(.*\)/\1/g' \
  | base64 -d - \
  | jq --raw-output .e \
  | base64 -d - \
  | xxd -
00000000: 74bc 1bfc 1ebe 7be1 5cdc fc1e 0e49 85eb  t.....{.\....I..
00000010: aecf 5d81 d65a 52b0 8ab5 e87e 2fc4 a443  ..]..ZR....~/..C
00000020: 2ee1 d0de 5419 c97b eed8 84a6 ea0a d9    ....T..{.......

Hopefully this answers your question!

jstrieb avatar Sep 11 '23 01:09 jstrieb

Hopefully this answers your question!

Thanks jstrieb for the answer,it really helped me.

cool-dev-guy avatar Sep 11 '23 16:09 cool-dev-guy

hey @jstrieb ,i have a doubt about encryption,is it possible to encrypt a string(length < 280chars) to an encrypted string of length<280 characters?

cool-dev-guy avatar Sep 28 '23 02:09 cool-dev-guy