-- Leo's gemini proxy
-- Connecting to gemini.circumlunar.space:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini
CSRF (Cross-Site Request Forgery) is, briefly, a way of doing malicious stuff on behalf of an user by making them do a request by clicking on a link or otherwise.
Unsurprisingly, this is a problem for Gemini too.
Some sites are starting to use INPUT (10) as an effectful request type, for example for posting a comment or liking a page. Unfortunately, since the input is passed as query string, there is no way to determine if it actually came from the user or if it was pre-filled with a malicious link.
For example, if gemini://example.org/post was an endpoint for adding a comment, I could put in my site a link to gemini://example.org/post?SPAM and whoever clicked that link would unknowingly comment "SPAM". A redirect would be even more stealthier.
Again, since there's no "Referer" equivalent on Gemini (for good reasons), it's impossible to detect this attack with simple urls like in the previous example.
Moreover, since in Gemini there's no difference between a read-only request and an effectful one, even crawlers are going to trigger that link and post "SPAM" on each update!
Add in authentication/authorization and this all becomes 1000 times worse.
There are sites that are vulnerable to this attack already.
The crawler problem can simply be avoided with a robots.txt (if the crawlers are well-behaved).
To completely (?) fix the issue, the same method that's used on the web can be implemented.
example.org/post redirects to example.org/nonce/<some_random_nonce>
example.org/nonce/<some_random_nonce> will actually ask the user for input and redirect them to the success page
nonces expire after a few minutes and are hard to guess
optionally, check that the nonce was generated and used by the same IP
in any case, IP throttling/blocking is implemented on the nonce generation endpoint
auth* has to be done in both endpoints
This way, a malicious actor has to first get a fresh nonce before tricking the user into visiting the /nonce endpoint.
As an example, this is already implemented (minus the blocking, plz do not abuse) in:
The web failed to natively protect the user from this type of attack, having to resort to ugly hidden form inputs with nonces. Can we do better in Gemini?
The first thing that comes to mind is having a nonce as part of the META in the INPUT response (with a new 1x code), and then requiring the client to send it back. But this would require a separator, and we all know where this leads.
Feedback and ideas welcome!
-- Response ended
-- Page fetched on Thu Mar 28 10:47:12 2024