Skip to content

Commit 763d4a6

Browse files
authored
Add option to disable host validation. (#79)
Fixes #78
1 parent 3d9a847 commit 763d4a6

File tree

6 files changed

+122
-32
lines changed

6 files changed

+122
-32
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ jobs:
1818
3.6,
1919
3.7,
2020
3.8,
21+
3.9,
2122
]
2223
steps:
2324
- uses: actions/checkout@v2
24-
- uses: actions/setup-python@v1
25+
- uses: actions/setup-python@v2
2526
with:
2627
python-version: ${{ matrix.python-version }}
2728
- name: Install dependencies

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ name: Release
33
on:
44
push:
55
tags:
6-
- 'v[0-9]+.[0-9]+.[0-9]+'
6+
- v[0-9]+.[0-9]+.[0-9]+
77

88
jobs:
99
build:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v2
13-
- uses: actions/setup-python@v1
13+
- uses: actions/setup-python@v2
1414
with:
15-
python-version: 3.8
15+
python-version: 3.9
1616
- name: Set release version
1717
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
1818
- name: Create Release

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
## [0.15.0] - 2021-01-02
6+
### Added
7+
- Parameter to disable host validation in server.
8+
59
## [0.14.0] - 2020-09-23
610
### Changed
711
- Dropped Python 2.7 support.
@@ -58,7 +62,8 @@
5862
### Changed
5963
- Property, Action, and Event description now use `links` rather than `href`. - [Spec PR](https://github.com/WebThingsIO/wot/pull/119)
6064

61-
[Unreleased]: https://github.com/WebThingsIO/webthing-python/compare/v0.14.0...HEAD
65+
[Unreleased]: https://github.com/WebThingsIO/webthing-python/compare/v0.15.0...HEAD
66+
[0.15.0]: https://github.com/WebThingsIO/webthing-python/compare/v0.14.0...v0.15.0
6267
[0.14.0]: https://github.com/WebThingsIO/webthing-python/compare/v0.13.2...v0.14.0
6368
[0.13.2]: https://github.com/WebThingsIO/webthing-python/compare/v0.13.1...v0.13.2
6469
[0.13.1]: https://github.com/WebThingsIO/webthing-python/compare/v0.13.0...v0.13.1

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ifaddr>=0.1.0
22
jsonschema>=3.2.0
3-
pyee>=8.0.0
4-
tornado>=6.0.0
3+
pyee>=8.1.0
4+
tornado>=6.1.0
55
zeroconf>=0.28.0

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
setup(
1616
name='webthing',
17-
version='0.14.0',
17+
version='0.15.0',
1818
description='HTTP Web Thing implementation',
1919
long_description=long_description,
2020
url='https://github.com/WebThingsIO/webthing-python',
@@ -24,9 +24,9 @@
2424
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
2525
install_requires=[
2626
'ifaddr>=0.1.0',
27-
'pyee>=8.0.0',
2827
'jsonschema>=3.2.0',
29-
'tornado>=6.0.0',
28+
'pyee>=8.1.0',
29+
'tornado>=6.1.0',
3030
'zeroconf>=0.28.0',
3131
],
3232
classifiers=[
@@ -37,6 +37,7 @@
3737
'Programming Language :: Python :: 3.6',
3838
'Programming Language :: Python :: 3.7',
3939
'Programming Language :: Python :: 3.8',
40+
'Programming Language :: Python :: 3.9',
4041
],
4142
license='MPL-2.0',
4243
project_urls={

webthing/server.py

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,25 @@ def get_name(self):
8686
class BaseHandler(tornado.web.RequestHandler):
8787
"""Base handler that is initialized with a thing."""
8888

89-
def initialize(self, things, hosts):
89+
def initialize(self, things, hosts, disable_host_validation):
9090
"""
9191
Initialize the handler.
9292
9393
things -- list of Things managed by this server
9494
hosts -- list of allowed hostnames
95+
disable_host_validation -- whether or not to disable host validation --
96+
note that this can lead to DNS rebinding
97+
attacks
9598
"""
9699
self.things = things
97100
self.hosts = hosts
101+
self.disable_host_validation = disable_host_validation
98102

99103
def prepare(self):
100104
"""Validate Host header."""
101105
host = self.request.headers.get('Host', None)
102-
if host is not None and host.lower() in self.hosts:
106+
if self.disable_host_validation or (
107+
host is not None and host in self.hosts):
103108
return
104109

105110
raise tornado.web.HTTPError(403)
@@ -169,20 +174,25 @@ def get(self):
169174
class ThingHandler(tornado.websocket.WebSocketHandler, Subscriber):
170175
"""Handle a request to /."""
171176

172-
def initialize(self, things, hosts):
177+
def initialize(self, things, hosts, disable_host_validation):
173178
"""
174179
Initialize the handler.
175180
176181
things -- list of Things managed by this server
177182
hosts -- list of allowed hostnames
183+
disable_host_validation -- whether or not to disable host validation --
184+
note that this can lead to DNS rebinding
185+
attacks
178186
"""
179187
self.things = things
180188
self.hosts = hosts
189+
self.disable_host_validation = disable_host_validation
181190

182191
def prepare(self):
183192
"""Validate Host header."""
184193
host = self.request.headers.get('Host', None)
185-
if host is not None and host in self.hosts:
194+
if self.disable_host_validation or (
195+
host is not None and host in self.hosts):
186196
return
187197

188198
raise tornado.web.HTTPError(403)
@@ -699,7 +709,8 @@ class WebThingServer:
699709
"""Server to represent a Web Thing over HTTP."""
700710

701711
def __init__(self, things, port=80, hostname=None, ssl_options=None,
702-
additional_routes=None, base_path=''):
712+
additional_routes=None, base_path='',
713+
disable_host_validation=False):
703714
"""
704715
Initialize the WebThingServer.
705716
@@ -713,12 +724,16 @@ def __init__(self, things, port=80, hostname=None, ssl_options=None,
713724
ssl_options -- dict of SSL options to pass to the tornado server
714725
additional_routes -- list of additional routes to add to the server
715726
base_path -- base URL path to use, rather than '/'
727+
disable_host_validation -- whether or not to disable host validation --
728+
note that this can lead to DNS rebinding
729+
attacks
716730
"""
717731
self.things = things
718732
self.name = things.get_name()
719733
self.port = port
720734
self.hostname = hostname
721735
self.base_path = base_path.rstrip('/')
736+
self.disable_host_validation = disable_host_validation
722737

723738
system_hostname = socket.gethostname().lower()
724739
self.hosts = [
@@ -749,49 +764,85 @@ def __init__(self, things, port=80, hostname=None, ssl_options=None,
749764
[
750765
r'/?',
751766
ThingsHandler,
752-
dict(things=self.things, hosts=self.hosts),
767+
dict(
768+
things=self.things,
769+
hosts=self.hosts,
770+
disable_host_validation=self.disable_host_validation,
771+
),
753772
],
754773
[
755774
r'/(?P<thing_id>\d+)/?',
756775
ThingHandler,
757-
dict(things=self.things, hosts=self.hosts),
776+
dict(
777+
things=self.things,
778+
hosts=self.hosts,
779+
disable_host_validation=self.disable_host_validation,
780+
),
758781
],
759782
[
760783
r'/(?P<thing_id>\d+)/properties/?',
761784
PropertiesHandler,
762-
dict(things=self.things, hosts=self.hosts),
785+
dict(
786+
things=self.things,
787+
hosts=self.hosts,
788+
disable_host_validation=self.disable_host_validation,
789+
),
763790
],
764791
[
765792
r'/(?P<thing_id>\d+)/properties/' +
766793
r'(?P<property_name>[^/]+)/?',
767794
PropertyHandler,
768-
dict(things=self.things, hosts=self.hosts),
795+
dict(
796+
things=self.things,
797+
hosts=self.hosts,
798+
disable_host_validation=self.disable_host_validation,
799+
),
769800
],
770801
[
771802
r'/(?P<thing_id>\d+)/actions/?',
772803
ActionsHandler,
773-
dict(things=self.things, hosts=self.hosts),
804+
dict(
805+
things=self.things,
806+
hosts=self.hosts,
807+
disable_host_validation=self.disable_host_validation,
808+
),
774809
],
775810
[
776811
r'/(?P<thing_id>\d+)/actions/(?P<action_name>[^/]+)/?',
777812
ActionHandler,
778-
dict(things=self.things, hosts=self.hosts),
813+
dict(
814+
things=self.things,
815+
hosts=self.hosts,
816+
disable_host_validation=self.disable_host_validation,
817+
),
779818
],
780819
[
781820
r'/(?P<thing_id>\d+)/actions/' +
782821
r'(?P<action_name>[^/]+)/(?P<action_id>[^/]+)/?',
783822
ActionIDHandler,
784-
dict(things=self.things, hosts=self.hosts),
823+
dict(
824+
things=self.things,
825+
hosts=self.hosts,
826+
disable_host_validation=self.disable_host_validation,
827+
),
785828
],
786829
[
787830
r'/(?P<thing_id>\d+)/events/?',
788831
EventsHandler,
789-
dict(things=self.things, hosts=self.hosts),
832+
dict(
833+
things=self.things,
834+
hosts=self.hosts,
835+
disable_host_validation=self.disable_host_validation,
836+
),
790837
],
791838
[
792839
r'/(?P<thing_id>\d+)/events/(?P<event_name>[^/]+)/?',
793840
EventHandler,
794-
dict(things=self.things, hosts=self.hosts),
841+
dict(
842+
things=self.things,
843+
hosts=self.hosts,
844+
disable_host_validation=self.disable_host_validation,
845+
),
795846
],
796847
]
797848
else:
@@ -800,42 +851,74 @@ def __init__(self, things, port=80, hostname=None, ssl_options=None,
800851
[
801852
r'/?',
802853
ThingHandler,
803-
dict(things=self.things, hosts=self.hosts),
854+
dict(
855+
things=self.things,
856+
hosts=self.hosts,
857+
disable_host_validation=self.disable_host_validation,
858+
),
804859
],
805860
[
806861
r'/properties/?',
807862
PropertiesHandler,
808-
dict(things=self.things, hosts=self.hosts),
863+
dict(
864+
things=self.things,
865+
hosts=self.hosts,
866+
disable_host_validation=self.disable_host_validation,
867+
),
809868
],
810869
[
811870
r'/properties/(?P<property_name>[^/]+)/?',
812871
PropertyHandler,
813-
dict(things=self.things, hosts=self.hosts),
872+
dict(
873+
things=self.things,
874+
hosts=self.hosts,
875+
disable_host_validation=self.disable_host_validation,
876+
),
814877
],
815878
[
816879
r'/actions/?',
817880
ActionsHandler,
818-
dict(things=self.things, hosts=self.hosts),
881+
dict(
882+
things=self.things,
883+
hosts=self.hosts,
884+
disable_host_validation=self.disable_host_validation,
885+
),
819886
],
820887
[
821888
r'/actions/(?P<action_name>[^/]+)/?',
822889
ActionHandler,
823-
dict(things=self.things, hosts=self.hosts),
890+
dict(
891+
things=self.things,
892+
hosts=self.hosts,
893+
disable_host_validation=self.disable_host_validation,
894+
),
824895
],
825896
[
826897
r'/actions/(?P<action_name>[^/]+)/(?P<action_id>[^/]+)/?',
827898
ActionIDHandler,
828-
dict(things=self.things, hosts=self.hosts),
899+
dict(
900+
things=self.things,
901+
hosts=self.hosts,
902+
disable_host_validation=self.disable_host_validation,
903+
),
829904
],
830905
[
831906
r'/events/?',
832907
EventsHandler,
833-
dict(things=self.things, hosts=self.hosts),
908+
dict(
909+
things=self.things,
910+
hosts=self.hosts,
911+
disable_host_validation=self.disable_host_validation,
912+
),
834913
],
835914
[
836915
r'/events/(?P<event_name>[^/]+)/?',
837916
EventHandler,
838-
dict(things=self.things, hosts=self.hosts),
917+
dict(
918+
things=self.things,
919+
hosts=self.hosts,
920+
disable_host_validation=self.disable_host_validation,
921+
),
839922
],
840923
]
841924

0 commit comments

Comments
 (0)