Re: WSGI 2.0 Round 2: requirements and call for interest

Cory Benfield <[email protected]> Tue, 5 Jan 2016 11:26:04 +0000
Newsgroups gmane.comp.python.web
Message-ID <[email protected]>
Forwarding this message from the django-developers list.

Hi Cory,

I’m not subscribed to web-sig but I read the discussion there. Feel free to forward my answer to the group if you think it’s useful.

I have roughly the same convictions as Graham Dumpleton. If you want to support HTTP/2 and WebSockets, don’t start with design decisions anchored in CGI. Figure out what a simple and flexible API for these new protocols would be, specify it, implement it, and make sure it degrades gracefully to HTTP/1. You may be able to channel most of the communication through a single generator, but it’s unclear to me that this will be the most convenient design.

If you want to improve WSGI, here’s a list of mistakes or shortcomings in PEP 3333 that you can take a stab at. There’s a general theme: for a specification that looks at the future, I believe that making modern PaaS-based deployments secure by default matters more than not implementing anything beyond what’s available in legacy CGI-based deployments.

1. WSGI is prone to header injection vulnerabilities issues by design due to the conversion of HTTP headers to CGI-style environment variables: if the server doesn’t specifically prevent it, X-Foo and X_Foo both become HTTP_X_Foo. I don’t believe it’s a good choice to destructively encode headers, expect applications to undo the damage somehow, and introduce security vulnerabilities in the process. If mimicking CGI is still considered a must-have — 1% of current Python web programmers may have heard about it, most of them from PEP 3333 — then that burden should be pushed onto the server, not the application.

2. More generally, I fail to see how mixing HTTP headers, server-related inputs, and environment variables in a dict adds values. It prevents iterating on each collection separately. It only makes sense if not offering more features than CGI is a design goal; in that case, this discussion doesn’t serve a purpose anyway. It would be nicer and possibly more secure if the application received separately:

a. Configuration information, which servers could read from environment variables by default for backwards compatibility, but could also get through more secure channels and restrict to what the application needs in order to better isolate it from the entire OS.
b. Server APIs mandated by the spec, per request.
c. HTTP headers, per request.

3. Stop pretending that HTTP is a unicode protocol, or at least stop ignoring reality when doing so. WSGI enforces ISO-8859-1-decoded str objects in the environ, which is just wrong. It’s all the more a surprising choice since this change was driven by Python 3, that UTF-8 is the correct choice, and that Python 3 defaults to UTF-8. Django has to re-encode and re-decode before doing anything with HTTP headers: https://github.com/django/django/blob/d5b90c8e120687863c1d41cf92a4cdb11413ad7f/django/core/handlers/wsgi.py#L231-L253

4. Normalize the way to tell the application about the original protocol, IP address and port. When dev and ops responsibilities are separate, this is clearly an ops responsibility, but due to the lack of standardization devs end up dealing with this problem in custom middleware, when they do it at all. Everyone keeps getting it wrong, which introduces security vulnerabilities. Also it always breaks silently on infrastructure changes.

5. Improve request / response length handling and connection closure. Armin and Graham have talked about in the past and know the topic better than I do. There’s also a rejected PEP by Armin which made sense to me.

As you can see from these comments, I don’t quite share the design choices that led to WSGI as it currently stands. I think it will be easier to build a new standard than evolve the current one.

I hope this helps!

Aymeric

_______________________________________________
Web-SIG mailing list
[email protected]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: https://mail.python.org/mailman/options/web-sig/gcpw-web-sig%40m.gmane.org
signature.asc (application/pgp-signature, 801 B)
-----BEGIN PGP SIGNATURE-----

iQIcBAEBCAAGBQJWi6hMAAoJEHD+F/imQ+FbOXkP+gLQ1UZdxi8GxBy0Y6qn3TUT
EKhuLJQVEqpqz0k5C1cWp+lbZYZtrYp6E5anhczz6A+02ZkmIyMpbK3CYimsaU8c
6skMFYb4IuDK5H7ZBaxQDYd6Zs8jWgaQs8GUnNkMw68SqBHw6KlYN84WKKnlzZXr
VUmHFE8vN3OEpFklOsjzc+lsjmVvoBzmhd2g4HzPHlaHw4T6a8TozqytyX9wSs2g
P027e4A7hrxuQBzV4EAsNIk71FqtyGhRdK/TXqNGvTQf8EDKnjK1+Qd22q2FIPvt
KwXWKe9T3IhY5GtDflJUru/uBaI6TPwtzgXFETQDYEehZKhqy/pVgvfQtf8JHmAj
eu6UAInEqV/U/NWQCgLRJJ5qnRUcKgPlU0W3Jgm8I3OVtmqdJonJ88YTs9c7aM2G
nV2uzC9iQSQAcf/YBRCqmNRA8Jv71Qij0/ddJNrjhwyIgHYBM4/d8Etxws9iFdxZ
g7NT01E0EQrlLeW3TtCpu/Gri518D9n0ate0+RKsl7Ne3d0tu+lFWMEC8t6LYyft
MkT9GSdmCHnLXZPo3OJOFW3+qo4HTUod+pRcr7leP8DWoy71JbS1WwcLskyAHKwM
K6DAViK6Hb+ReEGweW3Jy7429N6WIqvzmU9DhZbn4TpvgI/dh9XVHCEdk5gzlexL
qgvMsM2psU+TfvNSu3Fg
=+8Sb
-----END PGP SIGNATURE-----