Show HN: Link-lock – Distributed app to password-protect URLs
github.com
github.com
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!
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
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
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)
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.)
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!).
The suggestion of a data: URI might be a way to get guarantees similar to that of a static file, but in a URL.
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
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
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.
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.
> 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.
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.
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...
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 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!