My bookmarklet can be called from any website and basically allows the user to insert a row into his collection from afar - if he is logged in.
Now I want to enable CSRF protection for my site and since a bookmarklet is basically non-forged cross site request, I thought about how I could tell it apart from forged ones.
It's not a high-security environment, but I'm also interested in principle.
I thought I had a way to do it figured out, but then realised that it had problems galore.
Original idea
- generate a random key that is included in the bookmarklet-link. The key's hash is saved in the database. The random key allows access ONLY to the privilege of insertion into this collection and can't be used anywhere else.
- the bookmarklet loads a longer script from my server, so I could supply a CSRF prevention token this way
- require the user to be logged in
Problems
- If I have the bookmarklet key, do I need counter-CSRF tokens?
- Is there any way that I could protect the bookmarklet key if the user clicks his bookmarklet on a malicious website?
- I don't want username and password to be stored in the bookmarklet link, because anybody who has access to the computer would get the password as well then, so I decided on the random key.
- but if I store only the hash, I cannot generate the same bookmarklet link twice, so when the user wants a bookmarklet in another browser/computer he tediously has to import the link from the old one or break support for the old one.
- but I shouldn't store the cleartext key, because someone who gains access to the database could use this key to insert rows into accounts that don't belong to him.
- Possible solution I could ask the user to provide his password anytime he creates the bookmarklet and hash the password many times and put that hash in the URL and put the hash of that hash my database. But of course this opens much worse security holes.
- I could do this with something like "Mother's maiden name" instead
- I cannot use bcrypt for hashing because of the random salt, right? What hash function would be right? Or would you dismiss the whole idea?
- If I leave the bookmarklet key out, a malicious website could simply embed the bookmarklet and extract a valid CSRF token from it, right?
Better ideas? Or can't you have CSR without the F?
Edit, specified use case
One thing I simply didn't think about, is the usage of an iframe as suggested by Sripathi Krishnan.
I had not specified my use case, so yes, an iframe is a valid solution to the aforementioned problem.
However, actually my bookmarklet at the moment does do some basic interaction with the website at runtime (meaning the form is there already and the user can change his selection in the website DOM which should change the form). I'm ready to dismiss this functionality for my use case, if it turns out, there's no reasonably-secure way to tell apart forged from non-forged cross-site requests - but I'm still interested on a theoretical level.