mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 19:56:48 +00:00
fix(console): socketiod refuses a request without a signed-in session
Engine.IO accepts a connection, and holds one of socketiod's 40 threads for it, from its first request; the console token is checked only in Socket.IO's connect(), which a client need never send. Anyone who could reach the panel, without an account, could open 40 websockets, answer their pings, and no serial console would open for anybody (checked: the 41st handshake got no answer until they were closed). The daemon's WSGI app now refuses a request whose session cookie names no signed-in user, with 403, before Engine.IO sees it; the page always sends that cookie. A token without its session no longer connects either, as for novncd. Checked again: 60 such websockets are each answered 403 at once and hold nothing. The process tests sign their client in with a session cookie, as a browser; python-socketio sends a custom Cookie header only with its first request, so the client gets a cookie jar instead.
This commit is contained in:
parent
bb490101fd
commit
4f7bca9754
3 changed files with 59 additions and 14 deletions
|
|
@ -31,7 +31,7 @@ from gunicorn.app.base import BaseApplication # noqa: E402
|
|||
from django import db # noqa: E402
|
||||
from django.conf import settings # noqa: E402
|
||||
|
||||
from console.tokens import authorize # noqa: E402
|
||||
from console.tokens import authorize, session_user_id # noqa: E402
|
||||
|
||||
CONSOLECALLBACK = os.path.join(ROOT_PATH, "conf", "daemon", "consolecallback")
|
||||
LOG_FD = os.dup(2) # this daemon's stderr: a worker logs there on its fd 3
|
||||
|
|
@ -202,6 +202,23 @@ def disconnect(sid, reason=None):
|
|||
stop(sid)
|
||||
|
||||
|
||||
def signed_in_only(app):
|
||||
"""Engine.IO holds a connection, and one of the threads, from its first
|
||||
request; Socket.IO's connect() checks the token only after that. A request
|
||||
without a signed-in session is refused before it takes a thread: without
|
||||
this, anyone could hold every thread and no console would open."""
|
||||
def wsgi(environ, start_response):
|
||||
try:
|
||||
signed_in = session_user_id(environ.get("HTTP_COOKIE")) is not None
|
||||
finally:
|
||||
db.close_old_connections()
|
||||
if not signed_in:
|
||||
start_response("403 Forbidden", [("Content-Type", "text/plain")])
|
||||
return [b"Sign in to open a serial console\n"]
|
||||
return app(environ, start_response)
|
||||
return wsgi
|
||||
|
||||
|
||||
class Server(BaseApplication):
|
||||
"""gunicorn with one worker (the sessions live in it); a thread per connection."""
|
||||
|
||||
|
|
@ -217,7 +234,7 @@ class Server(BaseApplication):
|
|||
self.cfg.set("control_socket_disable", True)
|
||||
|
||||
def load(self):
|
||||
return socketio.WSGIApp(sio)
|
||||
return signed_in_only(socketio.WSGIApp(sio))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue