tl;dr, I’m posting this Lemmy issue that proposes a CORS change to allow Lemmy web clients to work with Lemmy servers without needing a proxy (possible security risk). Please show your support by +1ing the issue and the PR!
Issue link: https://github.com/LemmyNet/lemmy/issues/3109 PR link: https://github.com/LemmyNet/lemmy/pull/3421
Background
The web has many security features, and one of them is CORS, or Cross-Origin Resource Sharing. CORS ensures that when you click a button on a website in your browser, your account information isn’t immediately compromised. It’s one of many layers that protect your information from malicious actors.
Lemmy currently has this feature. Its CORS is configured to reject HTTP requests from an origin that is not what it expects. For example, if I’m on cool-lemmy-client.com
and I request a list of posts from beehaw.org
, the browser will reject the request. This is because beehaw.org
is telling the browser "hey, this request is only valid if it’s made within the beehaw.org
website, otherwise reject it!
This effectively means that third-party Lemmy web clients cannot talk to any Lemmy server. It’s impossible because those web clients are hosted outside of Lemmy servers, so the browser will refuse any interaction with those Lemmy servers.
Why Wefwef works
Wefwef is a third-party web client. It also runs in the web browser, and yet it works. How does it do that?
It turns out that Wefwef actually runs a proxy in the middle. The browser essentially hits this proxy instead, and the proxy makes the request on behalf of the browser. When it returns data, the proxy simply passes that data back and tells the browser that its origin is allowed.
This works because CORS is a browser thing: requests are rejected in the browser, not anywhere else, and because the proxy is its own server and not a browser, it’s not affected by CORS. This is also why applications like Jerboa work perfectly well.
Note: This is not to say anything about Wefwef! In fact, the developer of Wefwef expresses the same opinion!
Why proxies are bad
There are a myriad of issues that come with running a proxy for a web client, but it can be boiled down to 3 quick points:
- It creates a single point of load. All users of a particular web client now have to rely on a particular CORS proxy, and that puts a lot of load on that proxy.
- It exposes sensitive data to more parties. Specifically, CORS proxy operators (often the application maintainers) can see any information passed through it, including user tokens! Theoretically, they can steal your account.
- It is extra work for application maintainers to also maintain and scale CORS proxies.
Why it doesn’t make sense
Restrictive CORS doesn’t make sense for Lemmy. It is not an effective way to block third-party clients, since it is only a browser restriction. But people can still run proxies for their web applications, and that just makes things worse for everyone!
Lemmy doesn’t benefit from restrictive CORS.
Why it’s not a security problem
I said above that CORS helps prevent scenarios where your account information is stolen just by clicking a random button. However, this does not apply to Lemmy! To explain why, I need to look at how Lemmy (or any website) knows who you are.
Lemmy uses a JSON Web Token (JWT). Simply put, it’s a piece of text that tells the server “this is user X”, which is then cryptographically signed by the server, meaning it can’t be altered by anyone else without also breaking the signature. This allows the server to trust that if the signature is valid, then user X’s claim can be trusted.
Typically, the browser can send this token in two ways:
- It can do so using cookies. The server tells the browser “hey, store this token”, and later requests made by the browser will also include this token.
- It can do this by manually appending the token somewhere in the request, usually in the
Authorization
header. The application is usually the one that receives the token and manually stores it somewhere. It then manually reads this token back when it needs to and appends it to its requests.
Applications that implement the first method would be vulnerable to the aforementioned security problem if CORS didn’t exist: the browser could append the cookie to every subsequent request, including requests from other sites! This means that if I go to seemingly-legit.com
and the site makes a request to beehaw.org
, that request will be made on my behalf without my knowledge!
Fortunately, we can tune CORS so that we can still make requests to beehaw.org
without randomly leaking user data! Specifically, CORS has a separate header that tells the browser not to send cookies, even if it allows requests from anywhere (Access-Control-Allow-Credentials
vs. Access-Control-Allow-Origin
). This is what Lemmy PR does.
Applications implementing the second method may or may not be vulnerable:
- If it stores the token in its local storage, then only it can see that token. The browser does this by giving each origin (domain, e.g. google.com) a completely separate local store. Discord is one of the many applications that does this.
- If it stores the token in the browser’s cookie store, then it behaves the same as the first method. The only difference is that instead of the server telling the browser to set the cookie, it’s the application code running on the browser that sets the cookie.
Lemmy stores tokens in the cookies. As long as we’re careful about which CORS headers we return, the browser won’t leak them!
What we should do
Lemmy issue #3109 discusses this issue. You can show your support by responding with a thumbs up (+1) or a heart.
I have also created Lemmy PR #3421 which fixes this problem directly in code. You can also show your support by responding to this PR with a thumbs up or a heart.
I’m currently developing a Lemmy web client, and I need the CORS changes merged in order to use it with Lemmy instances running v0.18 or newer. Having this merged would save me a lot of time and effort. The developer of Wefwef has expressed the same opinion. Please consider supporting the application developers by upvoting these issues!