Tornado: web: Remove version from server header

Created on 13 Oct 2020  路  4Comments  路  Source: tornadoweb/tornado

Hi all

I would like to know how I can hide the http headers of Jupyterhub since it appears in Server: Tornado 5.1.1, I do not want the tornado version to appear

Thanks a lot

Most helpful comment

Use a custom tornado.web.OutputTransform to customize or remove the default Server header. It will apply to _all_ outgoing responses.

from tornado import ioloop, web


class ServerHeaderTransform(web.OutputTransform):
    def transform_first_chunk(self, status_code, headers, chunk, finishing):
        headers.pop('Server')
        return status_code, headers, chunk


app = web.Application(transforms=[ServerHeaderTransform])
app.listen(8000)
ioloop.IOLoop.current().start()
$ curl -v localhost:8000
*   Trying ::1:8000...
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.73.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 17 Nov 2020 21:18:02 GMT
< Content-Length: 69
<
* Connection #0 to host localhost left intact
<html><title>404: Not Found</title><body>404: Not Found</body></html> 

All 4 comments

You can override set_default_headers() in the RequestHandler sub-classes, and set or clear the Server response header there. This would have to be done in the Jupyter code base.

You could perhaps request that project to provide a config option, but they are probably not interested: https://github.com/jupyterhub/jupyterhub/issues/1674 - you probably want to put it behind a reverse-proxy: https://jupyterhub.readthedocs.io/en/stable/reference/config-proxy.html

set_default_headers is awkward to use for this purpose because you'd need to use subclasses of StaticFileHandler, RedirectHandler, etc. If you care about the server header, you should really be running behind a proxy that gives you a centralized place to control it.

This request comes up periodically - security compliance checklists often say you should hide version numbers here. I think that's generally silly, but on the other hand there's no strong reason to include the version in the first place. I think we should probably at least remove the version from the server header, and maybe just remove it completely.

Use a custom tornado.web.OutputTransform to customize or remove the default Server header. It will apply to _all_ outgoing responses.

from tornado import ioloop, web


class ServerHeaderTransform(web.OutputTransform):
    def transform_first_chunk(self, status_code, headers, chunk, finishing):
        headers.pop('Server')
        return status_code, headers, chunk


app = web.Application(transforms=[ServerHeaderTransform])
app.listen(8000)
ioloop.IOLoop.current().start()
$ curl -v localhost:8000
*   Trying ::1:8000...
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.73.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 17 Nov 2020 21:18:02 GMT
< Content-Length: 69
<
* Connection #0 to host localhost left intact
<html><title>404: Not Found</title><body>404: Not Found</body></html> 

Oh, I had forgotten all about OutputTransforms. That would work, although OutputTransform is undocumented and I've never really considered them as part of the web module's public API so I wouldn't want to encourage this (the HTTPMessageDelegate interfaces would be a supported way to do the same thing). Better to just change the source to stop emitting the server header completely.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bdarnell picture bdarnell  路  3Comments

jonathon-love picture jonathon-love  路  5Comments

viswamy picture viswamy  路  6Comments

kmike picture kmike  路  6Comments

AbsoluteVirtue picture AbsoluteVirtue  路  5Comments