Flask-socketio: 'sessions.py' example makes 400 errors

Created on 5 Aug 2019  路  13Comments  路  Source: miguelgrinberg/Flask-SocketIO

hello, miguel!

I'm testing your flask-socketio 'sessions.py' example.
I modified a single line below.

socketio.run(app, host="0.0.0.0", port=10001, debug=True)

I'm working on aws and I have one ALB, one server.
Do you recognize any suspicious parts?
Please help me.

  • server log
$ python sessions.py
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 447-673-972
172.31.26.106 - - [2019-08-05 16:06:59] "GET /status HTTP/1.1" 200 234 0.002048
172.31.9.8 - - [2019-08-05 16:06:59] "GET /session HTTP/1.1" 200 305 0.016384
172.31.9.8 - - [2019-08-05 16:07:02] "GET /session HTTP/1.1" 200 305 0.001257
172.31.9.8 - - [2019-08-05 16:07:03] "GET /socket.io/?EIO=3&transport=polling&t=MnYYBcV HTTP/1.1" 200 313 0.000406
172.31.9.8 - - [2019-08-05 16:07:03] "POST /socket.io/?EIO=3&transport=polling&t=MnYYBcj&sid=654afcf290c64963bd1c57055048dd03 HTTP/1.1" 400 122 0.000098
172.31.9.8 - - [2019-08-05 16:07:04] "POST /socket.io/?EIO=3&transport=polling&t=MnYYBry&sid=654afcf290c64963bd1c57055048dd03 HTTP/1.1" 400 122 0.000134
172.31.9.8 - - [2019-08-05 16:07:05] "GET /session HTTP/1.1" 200 305 0.001230
172.31.9.8 - - [2019-08-05 16:07:05] "GET /socket.io/?EIO=3&transport=polling&t=MnYYC6N HTTP/1.1" 200 313 0.000272
172.31.9.8 - - [2019-08-05 16:07:05] "POST /socket.io/?EIO=3&transport=polling&t=MnYYC6e&sid=df8b09256c964c208c0f86c2717e0731 HTTP/1.1" 400 122 0.000155
172.31.9.8 - - [2019-08-05 16:07:06] "POST /socket.io/?EIO=3&transport=polling&t=MnYYCL3&sid=df8b09256c964c208c0f86c2717e0731 HTTP/1.1" 400 122 0.000130
172.31.9.8 - - [2019-08-05 16:07:08] "GET /socket.io/?EIO=3&transport=polling&t=MnYYCr7 HTTP/1.1" 200 313 0.000331
172.31.9.8 - - [2019-08-05 16:07:08] "GET /session HTTP/1.1" 200 305 0.001190
172.31.9.8 - - [2019-08-05 16:07:08] "POST /socket.io/?EIO=3&transport=polling&t=MnYYCrK&sid=9bcc46f6e631400ca2496b6f98f72e6c HTTP/1.1" 400 122 0.000101
172.31.9.8 - - [2019-08-05 16:07:08] "GET /status HTTP/1.1" 200 234 0.001332
172.31.9.8 - - [2019-08-05 16:07:09] "POST /socket.io/?EIO=3&transport=polling&t=MnYYD4c&sid=9bcc46f6e631400ca2496b6f98f72e6c HTTP/1.1" 400 122 0.000135
  • client error
    image

  • response headers

content-length: 11
content-type: text/plain
date: Mon, 05 Aug 2019 16:02:43 GMT
set-cookie: AWSALB=Pi/jFkBePFRkIaftzrjjSFgkzHo0KHT34UBGqWS1QJrITr2pWlEX3b4KrE8OAtlHy87yqjU1GhuMhIOgjw4pFC7sdRtzakwRchuZCcpBUGKOiU1QGw3X+mbHVyvH; Expires=Mon, 12 Aug 2019 16:02:43 GMT; Path=/
status: 400
  • request headers
:authority: dev-bridge.bridgelabs.io
:method: POST
:path: /socket.io/?EIO=3&transport=polling&t=MnYXCE9&sid=6e3051f75a1146839bf28e80af6057c8
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
cache-control: no-cache
content-length: 20
content-type: text/plain;charset=UTF-8
cookie: io=6e3051f75a1146839bf28e80af6057c8; _ga=GA1.2.1989917511.1548125620; _gid=GA1.2.1324187863.1564967017; session=eyJfZnJlc2giOmZhbHNlLCJjb3VudGVyIjoyN30.XUg_wA.AuaUMJKQqyeL4mei8DwB_AH1XuY; AWSALB=rmUhRmVLgL3GC42AX5lP7O4GCFxM9RGQj7I3azc9GdOd/krph2oEcJwzQnv2KkSF5qxp5t5z6Yr7H5PDNM8bbQspc4gOsW2ZhELwP9MllBvYhQv6W9mThUMaT1DN
origin: https://dev-bridge.bridgelabs.io
pragma: no-cache
referer: https://dev-bridge.bridgelabs.io/
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36

always thank you.

question

Most helpful comment

For anyone just adding cors_allowed_origins='*' I'd like to ask you to think about what you are doing. This is basically saying that your server will allow connections from any origins. Depending on how you do authentication, this can enable CSRF attacks against your users.

If you only receive requests from one or two origins, then don't allow all origins, just allow these explicitly. That's a much more secure configuration that does not leave you vulnerable to attacks.

Examples:

1) to configure a single allowed origin:

cors_allowed_origins='https://example.com'

2) to configure multiple allowed origins:

cors_allowed_origins=['https://example1.com', 'https://example2.com']

Hope this helps!

All 13 comments

You are doing a cross-origin connection to the server. This used to be allowed by default, but for security reasons it is not anymore. Now you have to configure your allowed origins, or if you don't care about security, allow all origins by passing cors_allowed_origins='*' when you create your Socket.IO server.

miguel,

Does your flask-socketio sessions example needs cors handling?
This code is yours as is.
It looked not requires cors.
You know that jQuery ajax calls '/session' and socket.io calls '/socket.io' on sessions.html.
The client sessions.html and serverside '/session' and '/socket.io' is same origin.

Please let me know how you recognize I'm doing a cross-origin connection?

miguel,

I added a line to handle cors issue like below.

if __name__ == '__main__':
    import flask_cors; flask_cors.CORS(app, resources={r"/*":{"origins":"*"}})
    socketio.run(app, host="0.0.0.0", port=10001, debug=True)

But the problem remains.
Please help me slightly more.

You are doing a cross-origin connection to the server. This used to be allowed by default, but for security reasons it is not anymore. Now you have to configure your allowed origins, or if you don't care about security, allow all origins by passing cors_allowed_origins='*' when you create your Socket.IO server.

Isn't that a breaking change?
My code works fine with 4.2.1 but not work with 4.3.0

@miguelgrinberg

Sorry, I didn't understand your answer for 'cors_allowed_origins'.
I didn't know flask-socketio initializer has this option and recognize it by @NateScarlet's reply.

I've tried this option and I got another server error.

app = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'
app.config['SESSION_TYPE'] = 'filesystem'
login = LoginManager(app)
Session(app)
socketio = SocketIO(app, manage_session=False, cors_allowed_origins='*')


class User(UserMixin, object):
    def __init__(self, id=None):
        self.id = id
  • server log
$ python sessions.py
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 447-673-972
172.31.13.180 - - [2019-08-06 07:11:25] "GET /status HTTP/1.1" 200 234 0.001716
172.31.13.180 - - [2019-08-06 07:11:29] "GET / HTTP/1.1" 200 6809 0.020376
172.31.13.180 - - [2019-08-06 07:11:32] "GET /session HTTP/1.1" 200 305 0.001329
172.31.13.180 - - [2019-08-06 07:11:32] "GET / HTTP/1.1" 200 6809 0.001107
172.31.13.180 - - [2019-08-06 07:11:37] "GET /session HTTP/1.1" 200 305 0.001283
172.31.13.180 - - [2019-08-06 07:11:40] "GET /session HTTP/1.1" 200 305 0.001264
172.31.13.180 - - [2019-08-06 07:11:41] "POST /session HTTP/1.1" 204 257 0.001342
172.31.13.180 - - [2019-08-06 07:11:43] "GET /session HTTP/1.1" 200 299 0.001278
172.31.13.180 - - [2019-08-06 07:11:45] "POST /session HTTP/1.1" 204 257 0.001149
172.31.13.180 - - [2019-08-06 07:11:46] "GET /session HTTP/1.1" 200 305 0.001286
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/gevent/pywsgi.py", line 976, in handle_one_response
    self.run_application()
  File "/usr/lib64/python2.7/site-packages/gevent/pywsgi.py", line 923, in run_application
    self.result = self.application(self.environ, self.start_response)
  File "/usr/lib64/python2.7/site-packages/flask/app.py", line 2463, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/lib64/python2.7/site-packages/flask_socketio/__init__.py", line 46, in __call__
    start_response)
  File "/usr/lib/python2.7/site-packages/engineio/middleware.py", line 60, in __call__
    return self.engineio_app.handle_request(environ, start_response)
  File "/usr/lib/python2.7/site-packages/socketio/server.py", line 526, in handle_request
    return self.eio.handle_request(environ, start_response)
  File "/usr/lib/python2.7/site-packages/engineio/server.py", line 411, in handle_request
    cors_headers = self._cors_headers(environ)
  File "/usr/lib/python2.7/site-packages/engineio/server.py", line 610, in _cors_headers
    headers = [('Access-Control-Allow-Origin', environ['HTTP_ORIGIN'])]
KeyError: 'HTTP_ORIGIN'
2019-08-06T07:11:47Z {'REMOTE_PORT': '7398', 'HTTP_HOST': 'dev-bridge.bridgelabs.io', 'REMOTE_ADDR': '172.31.13.180', (hidden keys: 29)} failed with KeyError

172.31.13.180 - - [2019-08-06 07:11:47] "GET /socket.io/?EIO=3&transport=polling&t=MnbnGY0 HTTP/1.1" 500 161 0.002029

What do you think about this?

Isn't that a breaking change?
My code works fine with 4.2.1 but not work with 4.3.0

Yes, it is a breaking change for some people. Never said that it wasn't. I had to address a security problem.

The error that you get with HTTP_ORIGIN is already fixed, please upgrade flask-socketio, python-socketio and python-engineio to their latest releases.

@miguelgrinberg

thank you.
I resolved my issue by upgrading python-engineio version to 3.9.3.
It was 3.9.0 before.

It works fine at my environment under flask-socketio==4.2.0, python-socketio==4.3.0 and python-engineio==3.9.3

always thank you very much, miguel.

Version number of this project look like a [semver] version.
According to [semver] spec, breaking change should cause a major version incrementation:
4.3.0 should be 5.0.0.
It's confusing to have a breaking change in minor version update.

@NateScarlet It's a security bug. Do you prefer that I leave the 4.x open to CSRF attacks?

why not just deprecate the 4.x, version number is cheap.

And break every person who has a 4.x listed in a requirements file? And by the way, this also affects the 3.x, 2.x and 1.x, the problem is actually a vulnerability in the WebSocket protocol that needs to be compensated with a server-side fix, not an actual bug in this package.

So basically you are suggesting that to comply with semantic versioning (which I never said I adhere to, anyway) I deprecate every single version of this package that has been released to date, and then release a 5.0? How is that not a much bigger problem that would break pretty much everybody? Sorry, but I don't think there is a great solution to this problem, and I as the maintainer have to choose what I believe is the less disruptive path to get everyone upgraded.

After the upgrade, I also encountered the same problem 銆侷 reconfigured cors_allowed_origins='*' and it works fine now.

For anyone just adding cors_allowed_origins='*' I'd like to ask you to think about what you are doing. This is basically saying that your server will allow connections from any origins. Depending on how you do authentication, this can enable CSRF attacks against your users.

If you only receive requests from one or two origins, then don't allow all origins, just allow these explicitly. That's a much more secure configuration that does not leave you vulnerable to attacks.

Examples:

1) to configure a single allowed origin:

cors_allowed_origins='https://example.com'

2) to configure multiple allowed origins:

cors_allowed_origins=['https://example1.com', 'https://example2.com']

Hope this helps!

Was this page helpful?
0 / 5 - 0 ratings