Issue #27 on hold

Add possibility to reject a WebSocket request before the connection is established

Michael P. Jung
created an issue

I am using special crafted URL for the handover to a WebSocket connection. Now I want to check the given URL before the WebSocket connection is established. Right now there seams to be no way to reject a WebSocket connection before the connection is actually established.

I would propose that the library user needs to explicitly "open" or "accept" the connection.

Example:

def application(environ, start_response):    
    ws = environ['wsgi.websocket']
    if check_path(environ['PATH_INFO']):
        ws.open()
        websocket_main(ws)
        ws.close()
    else:
        start_response('404 Not Found', [])
        return []

Comments (14)

  1. Michael P. Jung reporter

    This does not really do what I want. I'm using gevent-websocket in https://bitbucket.org/terreon/mushroom/ and want to be able to be able to authenticate the user based on the URL.

    In mushroom the following happens:

    1. A bootstrap POST request is sent with the full authentication credentials. The response is JSON which contains the URL to connect to. For WebSocket sessions this is of the format ws://domain/session_id/
    2. The browser connects to the URL. If the session_id is not known at the server the connection should be rejected.

    This works fine so far but since the WebSocket connection is established before the session id check has been performed I guess this could be used easily for denial of service attacks.

  2. Jeffrey Gelens repo owner

    Ok, so I added the possibility to add a pre_start_hook. Change the echoserver.py in examples as follows:

    def hook(handler):
        raise Exception("Testing")
    
    WebSocketServer(("", 8000), echo_app, debug=True, pre_start_hook=hook).serve_forever()
    

    The WebSocketHandler is given as argument to the hook() callback, which should give you access to headers and environ to get the session_id.

  3. Michael P. Jung reporter

    I'd prefer a way to create an HTTP response directly from that handler. Would you mind if I create a pull request for this now that I know where to look?

  4. Jeffrey Gelens repo owner

    I don't think that's valid. Your browser is requesting a WS connection, so you shouldn't return a normal HTTP response imo.

    Probably the way you should handle this is by closing the website with a message:

    def close(self, code=1000, message='')
    

    This way you don't even need the hook.

    Pull requests are always welcome of course as long it doesn't break the websocket specs.

  5. David Heaps

    The example in the issue isn't really possible, since if the client is requesting something from the server... the connection is already open. However, I was able to use the pre_start_hook to reject connections if the authentication was not in the header... and send the 401 code to the browser, to request that authentication. I'm currently having an issue with it and SSL (issue 31), but it otherwise works great. I thought I'd share, since it was this issue that gave me the idea on how to do it. Thank you!

    This may be what you wanted... you can create an HTTP response from that pre_start_hook... it may not be proper implementation, but it works.

    Note that if the client web-page was not grabbed from the server, you must pass the authentication in the url... that doesn't work with SSL though... and really, probably shouldn't.

    Example: https://github.com/king-dopey/pytomation/blob/master/pytomation/interfaces/websocket_server.py

  6. Log in to comment