Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: Link-lock – Distributed app to password-protect URLs (github.com/jstrieb)
73 points by jstrieb on May 20, 2020 | hide | past | favorite | 24 comments


I originally made this as a complement to the URL Pages tool I made last summer, which stores an entire web page in its own URL.[0] Now, it is possible for URL Pages to be securely password-protected in a decentralized way.

Unlike other private bookmarking tools, this runs entirely in the browser, so it can't track users. Also, it only needs a static web host in order to run, minimizing the amount of infrastructure I have to maintain, which increases the likelihood it will still be running a decade from now.

Please note: I am a college student, not a security professional. There are certainly best-practices I am not aware of, and this is my first foray into using encryption. I have done my best to balance user experience and security, but am always looking for feedback!

[0]: https://news.ycombinator.com/item?id=20317840


> the URL Pages tool I made last summer, which stores an entire web page in its own URL

9 years ago (hashify): https://news.ycombinator.com/item?id=2464213 https://news.ycombinator.com/item?id=3407197

8 years ago (shortly): https://news.ycombinator.com/item?id=3834643 https://news.ycombinator.com/item?id=5696127


Amazing tool! And of course by the same person who did urlpages! Just this weekend I was exploring embedding a whole deterministic password gen into urlpages so I could have a syncable password manager with little infrastructure but obviously I'd be trusting whoever syncs my bookmarks... Now I don't need to worry anymore!


Glad to hear you like URL Pages! Because neither this project, nor that one use any tracking or analytics, my only indications that people are using it are GitHub stars, GitHub insights (with information about repository views), and the occasional message I receive on my website. I have many planned improvements for it, and knowing that others continue to find it useful is a great motivator.

I'm always looking for additional feedback on all of my projects, so don't hesitate to reach out with any additional thoughts, whether positive or negative! Contact info can be found on my website about page: https://jstrieb.github.io/about


I've never thought of something like this! it's awesome!


Now if we can have some kind of a timed-self-disappearing URL to go with this?

I had a rough idea outlined but this OP here effectively deals with any IDS/IPS trying to visit the link and access it. (And also deals with fixed retrieval count of such URL for my design)

https://egbert.net/blog/articles/one-time-url.html


At the risk of being annoyingly negative - as a webapp, this design does require you to trust the web server hosting it (it could just send you JS to steal your password!)

Instead, maybe generate a data: URI with the decryption code on it. (If this would make it too long, could still load the main JS from a server via XHR, but check the hash of it before executing.)


> this design does require you to trust the web server hosting it (it could just send you JS to steal your password!)

The author mentioned elsewhere in this thread that it's all static and client-side, so if that was a concern, you could just clone the repo and just open the HTML file in your web browser (no web server needed!).


Yeah, but when you're sending files around, you've already sort of lost the UX battle.

The suggestion of a data: URI might be a way to get guarantees similar to that of a static file, but in a URL.


Interesting concept, thanks for sharing.

It looks like the password is transformed to bytes by decoding base64, which is not a realistic assumption. You could use TextEncoder().encode() instead.

The nonradom iv is very dangerous, you could randomize that one and the salt every time, and read them from the additional data before decrypting. Never propose fixed values as an option


Thanks so much for the feedback! Based on this and tptacek's comment,[0] I will likely remove the ability to disable randomizing the IV in future versions. Luckily, this will not break any encrypted links generated thus far.

Unless I am misunderstanding your comment, I do actually use TextEncoder and TextDecoder objects for doing some ascii <-> Uint8Array conversion in the base64 library I wrote,[1] but I have found that they are not actually inverses, leading me to minimize their use. To be fair, I may just be doing something incorrectly. However, in a number of my test cases, I have found the following to be true:

  (new TextDecoder).decode((new TextEncoder).encode(someText)) != someText
Also, note that if the base64 decoding fails, there will be an error shown explaining that the encoded URL appears corrupted. Does this address what you mean about the password being transformed to bytes via base64?

[0]: https://news.ycombinator.com/item?id=23253488

[1]: https://github.com/jstrieb/link-lock/blob/master/b64.js#L41


Oh, `b64.asciiToBinary` tripped me off, I thought it was about base64, but it encodes any string using utf-8, which is fine for what you use it but a bit confusing to the reader.

About TextDecoder/TextEncoder not being the reverse of one another, I suspect you are not feeding it text but random bytes, which can cause that behaviour.


This is good feedback, I will make a note to adjust this later. Thanks!


While I like the idea, it does seem very gimmicky to me. The only real reason I see to use this, is ease of use, but then, why only encrypt URLs. Why not just make an easy tool to encrypt small text fragments?

That said, I does look like a good exercise and a nice way to get familiar with crypto in the browser. Kudos for making it.


From OPs comment

> I originally made this as a complement to the URL Pages tool I made last summer, which stores an entire web page in its own URL.[0] Now, it is possible for URL Pages to be securely password-protected in a decentralized way.

> [0]: https://news.ycombinator.com/item?id=20317840


I don't understand the "non-randomization of IVs" feature, since GCM is totally insecure if an IV is reused. Is this code deriving deterministic IVs from the plaintext or something? Or can keys simply not be reused? It seems like they can, if KDF salts are by default non-random.


Thanks for your comment! The basis for the feature is that it makes the generated URLs a few characters shorter – empirically, savings are on the order of 20-25 characters. Minor for most, but I don't purport to know what users will do with the tool, or if this length will make a difference.

Under the hood, once encryption is performed, the version number, encrypted data, salt and IV (if randomly-generated), and hint (if given) are JSON-stringified and base64-encoded for storage in the URL fragment. There is a hard-coded default salt and IV if the user chooses not to randomize, which means they don't need to be encoded in the object that is eventually stored in the URL, thus making the generated URL shorter.

Based on your comment, it seems hard-coding an IV and giving the user the ability to disable randomization may unnecessarily make unwitting users vulnerable. Would you recommend I remove the ability for users to disable randomization moving forward? Do you think I should just add a big warning if they try to uncheck the box instead? I'm open to suggestions.

In general, I'm very interested in all recommendations for best-practices, as the tool is under active development, and is a learning opportunity for me.


A hard-coded IV with AES-GCM is bad only if you're encrypting content with the same key.

Since you're deriving keys via a password, that would mean that two Link-Lock URL's protected with the same password _and_ using the same hard-coded IV would be vulnerable.

It's likely an infeasible attack, but definitely worth giving a warning to those who really want to cut back on those 20-25 characters.

Though since the URL fragment has _encrypted_ content, I think the users should understand up-front that the URL's will be long; it's impossible not to.


I haven't looked carefully at the design; in fact, I've only read enough of the code to see that there's a flag to disable IV randomization. I'm only here to say that GCM is completely insecure if IVs are ever reused.

https://toadstyle.org/cryptopals/63.txt


>it seems hard-coding an IV and giving the user the ability to disable randomization may unnecessarily make unwitting users vulnerable

Yes. There's not a great reason to disable the randomization here. You're safe if each link uses a new key, but if it was possible for a user to use the same key and IV for a different link, an attacker with access to the first link could now use it to access the second.

https://en.wikipedia.org/wiki/Stream_cipher_attacks#Chosen-I...


Is there a reason the password boxes are regular input fields and not password fields?


Thanks for your comment! When creating the encrypted URL, the password entry uses proper password fields, but the decryption prompt does not.

I originally made the decryption password prompt use a JavaScript window.prompt because I didn't want to risk users' hints posing an XSS vulnerability. Unfortunately, that means entering the password in the prompt is not done with a proper password field, and is instead done in plaintext.

Eventually, I hope to build out a better UI for decrypting links. Handling this is definitely on my list of planned improvements!


Cool idea! I love those small experiments.


This is so useful, thanks for making it!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: