-
Notifications
You must be signed in to change notification settings - Fork 715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lobby vulnerabilities #429
Comments
I will spend some time improving the lobby in general. I want to refactor the code too, and add more features. |
Thanks for looking into this @flamecoals! |
Should we look into JSON Web Tokens for auth stuff in general? |
JWT could be interesting. For now, might the following make sense to prevent leaking credentials?
|
@delucis Sounds good! |
Cool. It'll probably take me a little while to get to all of this, but I've found another bug with the database caching that's an easy fix, so I'll take care of that in the next couple of days. |
Thanks for looking into this, Chris!
…On Tue, Dec 17, 2019, 3:41 PM Chris Swithinbank ***@***.***> wrote:
Cool. It'll probably take me a little while to get to all of this, but
I've found another bug with the database caching that's an easy fix, so
I'll take care of that in the next couple of days.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#429>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABZULUVFKQ6UZWQ7ZO3CRLQZB7BLANCNFSM4H4PEXDQ>
.
|
* fix(server): Assign seat credentials when a player joins a room Addresses potential for leaking credentials identified in #429. Credentials for each seat are now set when a player joins a room and then deleted when the player leaves. * feat(server): Allow customised `generateCredentials` lobby config Setting a `generateCredentials` method in the lobbyConfig customises the credentials stored in gameMetadata and returned to players when the join a room. `generateCredentials` is called with Koa’s `ctx` object to allow credentials to depend on request content/headers, and can be asynchronous to permit calling third-party services. * feat(master): Allow asynchronous authentication checks * feat(server): Use options object to configure socket.io server transport * feat(server): Allow master’s auth option to be set via SocketIO * feat(server): Add `authenticateCredentials` option to server * refactor(server): Move `generateCredentials` option to Server factory * docs(api): Document custom authentication approaches * docs(api): Remove “custom” from Server API docs Co-authored-by: Nicolo John Davis <nicolodavis@gmail.com>
FYI, I just ran into a race condition mentioned previously on joining the rooms while developing this PR: Initially the code was running in memory and it was OK executing in parallel two users joining. However, when I started using Postgres, the two joins would execute in parallel the SQL to check the previous credential, and then both would write each user's credential only, making so one user would have no credential on the database. I had to change our server to do these requests serially to avoid this issue. But this could happen in the wild too, especially with moves if they happen very fast. We should have a concept of transactions on the adapter to avoid this issue. |
@flamecoals Hypothetically, anywhere that we read from storage, run code, then write to storage technically needs some kind of transaction API. This would be quite a bit of work (rewriting all the third-party storage implementations), but what might it look like from a high level? Something like this? await db.runTransaction(
// map of desired inputs to fetch from db
{ metadata: true },
// callback that is retried if inputs change and only writes when inputs haven’t changed
(writer, { metadata }) => {
metadata.players[playerID].credentials = 'foo';
writer.setMetadata(metadata);
}
); That might offer a much more flexible database API allowing transactions to be used more broadly, but I don’t know what support would look like or how easy it is to implement in each backend. |
I was looking at the code while developing a PR, and I think the Lobby endpoints have several vulnerabilities:
Leaking credentials
The credentials are initialized by playerID when the room is created, and does not change if hte user leaves or joins the room. So if a user leaves the room, they could possibly keep the credential, and when another user joins that room in their place, the previous user could play on behalf of the new user.
Reflective XSS for instance here:
if gameID is a javascript, then this javascript will be able to execute in the user browsers.
XSRF
It seems like it has some protection with API_SECRET, but this is very weak as it is a global for the whole server. An attacker can just check what API_SECRET is being returned by the frontend once and a server restart would be needed to change the credential. Also, this option is buried deep inside the code and not documented anywhere.
Race conditions
The "db" API has no interface for transactions or atomic checks, which leads to possible race conditions. Theoretically we could have two HTTP requests changing the state at the same time, and both executes their "checks" at the same time without seeing the change of each other states. This will definitely be a problem with several concurrent users, and specially if we need to scale to multiple servers accessing the database in parallel.
The text was updated successfully, but these errors were encountered: