Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web: Remove version from server header #2935

Open
Carl7189 opened this issue Oct 13, 2020 · 6 comments
Open

web: Remove version from server header #2935

Carl7189 opened this issue Oct 13, 2020 · 6 comments
Labels

Comments

@Carl7189
Copy link

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

@ploxiln
Copy link
Contributor

ploxiln commented Oct 14, 2020

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: jupyterhub/jupyterhub#1674 - you probably want to put it behind a reverse-proxy: https://jupyterhub.readthedocs.io/en/stable/reference/config-proxy.html

@bdarnell
Copy link
Member

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.

@bdarnell bdarnell changed the title How hide server headers web: Remove version from server header Oct 26, 2020
@nvllsvm
Copy link
Contributor

nvllsvm commented Nov 17, 2020

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> 

@bdarnell
Copy link
Member

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.

@itayB
Copy link

itayB commented Jul 12, 2021

Hi,

I'm using Tornado 6.0.4 and I tried the solution above but I've noticed that my Content-Encoding: gzip disappeared together with the Server header:

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


class MyApplication(Application):
    def __init__(self, *args, **kwargs) -> None:
        kwargs['compress_response'] = True
        kwargs['transforms'] = [ServerHeaderTransform]
        super().__init__(*args, **kwargs)

app = MyApplication()
app.listen(8000)
ioloop.IOLoop.current().start()

Without the kwargs['transforms'] = [ServerHeaderTransform] line I'm getting gzip responses as expected (when asking for a compressed response.

Any idea why it doesn't work together with the compress_response flag?

@nvllsvm
Copy link
Contributor

nvllsvm commented Jul 12, 2021

@itayB

Specifying the transforms kwarg is overrides the compress_response flag.

tornado/tornado/web.py

Lines 2040 to 2045 in aa9d32d

if transforms is None:
self.transforms = [] # type: List[Type[OutputTransform]]
if settings.get("compress_response") or settings.get("gzip"):
self.transforms.append(GZipContentEncoding)
else:
self.transforms = transforms

Use self.add_transform instead.

tornado/tornado/web.py

Lines 2128 to 2129 in aa9d32d

def add_transform(self, transform_class: Type["OutputTransform"]) -> None:
self.transforms.append(transform_class)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants