-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
test_hsts.rb
194 lines (156 loc) · 6.52 KB
/
test_hsts.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
require File.join(File.dirname(__FILE__), 'helper')
class TestSiteInspector < Minitest::Test
def setup
Typhoeus::Config.cache = SiteInspectorCache.new
end
# Official HSTS RFC:
# http://tools.ietf.org/html/rfc6797
should "parse the gold standard hsts header" do
gold = "max-age=31536000; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(gold)
# parsed:
assert_equal 31536000, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
# inferred:
assert_equal true, hsts[:enabled]
assert_equal true, hsts[:preload_ready]
end
should "parse other valid hsts headers" do
# not observed - allow quoted strings
gold = "max-age=\"31536000\"; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(gold)
assert_equal 31536000, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal true, hsts[:preload_ready]
# observed on uspsoig.gov - long, lowercase 'Subdomains'
header = "max-age=63072000; includeSubdomains; preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal 63072000, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal true, hsts[:preload_ready]
# not observed anywhere, but a stray semicolon should change nothing
header = "max-age=63072000; includeSubdomains; preload;"
hsts = SiteInspector.hsts_parse(header)
assert_equal 63072000, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal true, hsts[:preload_ready]
# observed on fws.gov
header = "max-age=0"
hsts = SiteInspector.hsts_parse(header)
assert_equal 0, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# not observed, but just in case
header = "max-age=0; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal 0, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# observed on www.bfelob.gov - 1 hour
header = "max-age=86400"
hsts = SiteInspector.hsts_parse(header)
assert_equal 86400, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# observed on wh.gov - not long enough
header = "max-age=3600;includeSubDomains;preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal 3600, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal false, hsts[:preload_ready] # too short!
# observed on healthcare.gov - no subdomains
header = "max-age=31536000;preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal 31536000, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal true, hsts[:preload]
assert_equal true, hsts[:enabled]
# judgment call: preload-ready means *automatically* preload-ready
assert_equal false, hsts[:preload_ready]
# observed on jamesmadison.gov - just includeSubDomains
header = "includeSubDomains"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
end
should "handle invalid hsts headers" do
# observed on whitehouse.gov
header = "max-age=3600;include_subdomains"
hsts = SiteInspector.hsts_parse(header)
assert_equal 3600, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal true, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# observed on www.tedcruz.org - no commas allowed!
# RFC specifies that invalid syntax is unprocessable,
# so no HSTS. Spaces are not valid characters unless helping
# separating directives, which only semicolons can do.
header = "max-age=15552000, includeSubDomains"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# not observed anywhere (yet!)
header = "max-age3600; includeSubDomains"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal true, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# not observed - single quotes are not allowed
header = "max-age='31536000'; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# not observed - neither is just one quote
header = "max-age=\"31536000; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# not observed - no quotes on max-age
header = "\"max-age\"=31536000; includeSubDomains; preload"
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age]
assert_equal false, hsts[:include_subdomains]
assert_equal false, hsts[:preload]
assert_equal false, hsts[:enabled]
assert_equal false, hsts[:preload_ready]
# fuzzing!
["312384761283746", 0, nil, "", "-1", "$!#@%!#}"].each do |header|
hsts = SiteInspector.hsts_parse(header)
assert_equal nil, hsts[:max_age], header
assert_equal false, hsts[:include_subdomains], header
assert_equal false, hsts[:preload], header
assert_equal false, hsts[:enabled], header
assert_equal false, hsts[:preload_ready], header
end
end
end