@thymian/rules-rfc-6797 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +158 -2
  2. package/dist/coverage.d.ts +291 -0
  3. package/dist/coverage.d.ts.map +1 -0
  4. package/dist/coverage.js +160 -0
  5. package/dist/coverage.js.map +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +29 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.d.ts +3 -0
  11. package/dist/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.d.ts.map +1 -0
  12. package/dist/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.js +12 -0
  13. package/dist/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.js.map +1 -0
  14. package/dist/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.d.ts +3 -0
  15. package/dist/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.d.ts.map +1 -0
  16. package/dist/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.js +39 -0
  17. package/dist/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.js.map +1 -0
  18. package/dist/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.d.ts +3 -0
  19. package/dist/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.d.ts.map +1 -0
  20. package/dist/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.js +35 -0
  21. package/dist/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.js.map +1 -0
  22. package/dist/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.d.ts +3 -0
  23. package/dist/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.d.ts.map +1 -0
  24. package/dist/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.js +24 -0
  25. package/dist/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.js.map +1 -0
  26. package/dist/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.d.ts +3 -0
  27. package/dist/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.d.ts.map +1 -0
  28. package/dist/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.js +14 -0
  29. package/dist/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.js.map +1 -0
  30. package/dist/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.d.ts +3 -0
  31. package/dist/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.d.ts.map +1 -0
  32. package/dist/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.js +19 -0
  33. package/dist/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.js.map +1 -0
  34. package/dist/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.d.ts +3 -0
  35. package/dist/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.d.ts.map +1 -0
  36. package/dist/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.js +25 -0
  37. package/dist/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.js.map +1 -0
  38. package/dist/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.d.ts +3 -0
  39. package/dist/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.d.ts.map +1 -0
  40. package/dist/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.js +22 -0
  41. package/dist/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.js.map +1 -0
  42. package/dist/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.d.ts +3 -0
  43. package/dist/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.d.ts.map +1 -0
  44. package/dist/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.js +14 -0
  45. package/dist/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.js.map +1 -0
  46. package/dist/rules/syntax/hsts-host-may-assert-include-subdomains.rule.d.ts +3 -0
  47. package/dist/rules/syntax/hsts-host-may-assert-include-subdomains.rule.d.ts.map +1 -0
  48. package/dist/rules/syntax/hsts-host-may-assert-include-subdomains.rule.js +35 -0
  49. package/dist/rules/syntax/hsts-host-may-assert-include-subdomains.rule.js.map +1 -0
  50. package/dist/rules/syntax/hsts-host-must-not-repeat-sts-directives.rule.d.ts +3 -0
  51. package/dist/rules/syntax/hsts-host-must-not-repeat-sts-directives.rule.d.ts.map +1 -0
  52. package/dist/rules/syntax/hsts-host-must-not-repeat-sts-directives.rule.js +33 -0
  53. package/dist/rules/syntax/hsts-host-must-not-repeat-sts-directives.rule.js.map +1 -0
  54. package/dist/rules/syntax/hsts-host-must-send-include-subdomains-without-value.rule.d.ts +3 -0
  55. package/dist/rules/syntax/hsts-host-must-send-include-subdomains-without-value.rule.d.ts.map +1 -0
  56. package/dist/rules/syntax/hsts-host-must-send-include-subdomains-without-value.rule.js +24 -0
  57. package/dist/rules/syntax/hsts-host-must-send-include-subdomains-without-value.rule.js.map +1 -0
  58. package/dist/rules/syntax/hsts-host-must-send-max-age-as-delta-seconds.rule.d.ts +3 -0
  59. package/dist/rules/syntax/hsts-host-must-send-max-age-as-delta-seconds.rule.d.ts.map +1 -0
  60. package/dist/rules/syntax/hsts-host-must-send-max-age-as-delta-seconds.rule.js +33 -0
  61. package/dist/rules/syntax/hsts-host-must-send-max-age-as-delta-seconds.rule.js.map +1 -0
  62. package/dist/rules/syntax/hsts-host-must-send-max-age-directive.rule.d.ts +3 -0
  63. package/dist/rules/syntax/hsts-host-must-send-max-age-directive.rule.d.ts.map +1 -0
  64. package/dist/rules/syntax/hsts-host-must-send-max-age-directive.rule.js +24 -0
  65. package/dist/rules/syntax/hsts-host-must-send-max-age-directive.rule.js.map +1 -0
  66. package/dist/rules/syntax/hsts-host-must-send-sts-header-conforming-to-grammar.rule.d.ts +3 -0
  67. package/dist/rules/syntax/hsts-host-must-send-sts-header-conforming-to-grammar.rule.d.ts.map +1 -0
  68. package/dist/rules/syntax/hsts-host-must-send-sts-header-conforming-to-grammar.rule.js +29 -0
  69. package/dist/rules/syntax/hsts-host-must-send-sts-header-conforming-to-grammar.rule.js.map +1 -0
  70. package/dist/rules/syntax/user-agent-must-enforce-hsts-policy.rule.d.ts +3 -0
  71. package/dist/rules/syntax/user-agent-must-enforce-hsts-policy.rule.d.ts.map +1 -0
  72. package/dist/rules/syntax/user-agent-must-enforce-hsts-policy.rule.js +15 -0
  73. package/dist/rules/syntax/user-agent-must-enforce-hsts-policy.rule.js.map +1 -0
  74. package/dist/rules/syntax/user-agent-must-ignore-unrecognized-sts-directives.rule.d.ts +3 -0
  75. package/dist/rules/syntax/user-agent-must-ignore-unrecognized-sts-directives.rule.d.ts.map +1 -0
  76. package/dist/rules/syntax/user-agent-must-ignore-unrecognized-sts-directives.rule.js +37 -0
  77. package/dist/rules/syntax/user-agent-must-ignore-unrecognized-sts-directives.rule.js.map +1 -0
  78. package/dist/rules/utils/headers.d.ts +7 -0
  79. package/dist/rules/utils/headers.d.ts.map +1 -0
  80. package/dist/rules/utils/headers.js +54 -0
  81. package/dist/rules/utils/headers.js.map +1 -0
  82. package/dist/rules/utils/redirect.d.ts +8 -0
  83. package/dist/rules/utils/redirect.d.ts.map +1 -0
  84. package/dist/rules/utils/redirect.js +150 -0
  85. package/dist/rules/utils/redirect.js.map +1 -0
  86. package/dist/rules/utils/results.d.ts +5 -0
  87. package/dist/rules/utils/results.d.ts.map +1 -0
  88. package/dist/rules/utils/results.js +14 -0
  89. package/dist/rules/utils/results.js.map +1 -0
  90. package/dist/rules/utils/sts-contexts.d.ts +12 -0
  91. package/dist/rules/utils/sts-contexts.d.ts.map +1 -0
  92. package/dist/rules/utils/sts-contexts.js +69 -0
  93. package/dist/rules/utils/sts-contexts.js.map +1 -0
  94. package/dist/rules/utils/sts-field-value.d.ts +17 -0
  95. package/dist/rules/utils/sts-field-value.d.ts.map +1 -0
  96. package/dist/rules/utils/sts-field-value.js +133 -0
  97. package/dist/rules/utils/sts-field-value.js.map +1 -0
  98. package/dist/rules/utils/transport.d.ts +4 -0
  99. package/dist/rules/utils/transport.d.ts.map +1 -0
  100. package/dist/rules/utils/transport.js +24 -0
  101. package/dist/rules/utils/transport.js.map +1 -0
  102. package/package.json +55 -4
@@ -0,0 +1,160 @@
1
+ // RFC 6797's denominator (ADR-0021 §5). RFC 6797 carries a real conformance
2
+ // clause (§3: a conformant host implements every requirement applicable to
3
+ // hosts), so its unit is a keyword paragraph — but only in the chapters a
4
+ // host can be held to. §6 (the header field's syntax), §7 (the server
5
+ // processing model) and §9.2 (the effective request URI) are the host's; §8
6
+ // and §13 are the user agent's processing model, which Thymian cannot
7
+ // observe; §11 and §12 open with "This section is non-normative."
8
+ //
9
+ // Counted from the document, never from the rules: derived by splitting
10
+ // https://www.rfc-editor.org/rfc/rfc6797.txt (November 2012) into
11
+ // paragraphs, dropping page headers and footers, and keeping every paragraph
12
+ // of §6, §7 and §9.2 that contains at least one of MUST, MUST NOT, REQUIRED,
13
+ // SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY or OPTIONAL. 14
14
+ // qualify, and no page break in those sections splits a paragraph. Two of
15
+ // them are NOTEs in §7 that quote a keyword to explain one; the counting
16
+ // rule counts them. Three of §6.1's are addressed to the user agent; each is
17
+ // a unit like any other.
18
+ //
19
+ // A unit's id is `<section>/<n>`: n is the paragraph's position among that
20
+ // section's keyword paragraphs, so the id is re-derivable from the counting
21
+ // rule alone.
22
+ //
23
+ // The per-rule entries arrive with the rules, grouped by the topic directory
24
+ // the rule lives in; a unit no entry covers renders as not yet covered.
25
+ import { defineCoverage } from '@thymian/core';
26
+ const units = {
27
+ '6.1/1': 'The STS header field indicates to a UA that it MUST enforce the HSTS Policy in regards to the host emitting the response.',
28
+ '6.1/2': 'All directives MUST appear only once in an STS header field.',
29
+ '6.1/3': 'UAs MUST ignore any STS header field containing directives, or other header field value data, that does not conform to the syntax.',
30
+ '6.1/4': 'If an STS header field contains directives not recognized by the UA, the UA MUST ignore them and process the recognized ones.',
31
+ '6.1.1/1': 'The REQUIRED max-age directive specifies how many seconds the UA regards the host as a Known HSTS Host.',
32
+ '6.1.1/2': "The max-age directive's REQUIRED value is delta-seconds (1*DIGIT), after quoted-string unescaping.",
33
+ '6.1.2/1': 'The OPTIONAL includeSubDomains directive is a valueless directive that extends the HSTS Policy to subdomains.',
34
+ '7.1/1': 'Over secure transport, an HSTS Host SHOULD include an STS header field that MUST satisfy the §6.1 grammar, and MUST include only one.',
35
+ '7.1/2': 'Establishing a Known HSTS Host MAY be accomplished by returning a valid STS header field over secure transport; a pre-loaded list MAY also be used.',
36
+ '7.1/3': 'NOTE: including the STS header field is a SHOULD to accommodate caches and load balancing.',
37
+ '7.2/1': 'Over non-secure transport, an HSTS Host SHOULD answer with a permanent redirect whose Location has the https scheme.',
38
+ '7.2/2': 'NOTE: the redirect is a SHOULD rather than a MUST because of redirect risks and deployment characteristics.',
39
+ '7.2/3': 'An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport.',
40
+ '9.2/1': 'Effective request URIs are compared per RFC 2616 §3.2.3, except that empty path components MUST NOT be treated as equivalent to an absolute path of "/".',
41
+ };
42
+ export default defineCoverage({
43
+ source: {
44
+ revision: 'RFC 6797 (November 2012)',
45
+ countingRule: 'One unit per paragraph of §6, §7 and §9.2 — the chapters addressed to the host — that contains a BCP 14 keyword.',
46
+ hasKeywordBasis: true,
47
+ },
48
+ units,
49
+ rules: {
50
+ // §6 — the header field's syntax.
51
+ 'rfc6797/user-agent-must-enforce-hsts-policy': {
52
+ covers: ['6.1/1'],
53
+ declared: { types: ['informational'], severity: 'error' },
54
+ },
55
+ 'rfc6797/hsts-host-must-not-repeat-sts-directives': {
56
+ covers: ['6.1/2'],
57
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
58
+ },
59
+ // 6.1/3 is addressed to the user agent, and its contrapositive is the
60
+ // host's: a header that does not conform is ignored, so the host MUST
61
+ // send one that does (7.1/1). One rule discharges both.
62
+ 'rfc6797/hsts-host-must-send-sts-header-conforming-to-grammar': {
63
+ covers: ['6.1/3', '7.1/1'],
64
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
65
+ },
66
+ // 6.1/4's contrapositive: a directive RFC 6797 does not define is one a
67
+ // user agent will skip. Heuristic, because a directive defined later, or
68
+ // recognised by some user agents, is not a defect.
69
+ 'rfc6797/user-agent-must-ignore-unrecognized-sts-directives': {
70
+ covers: ['6.1/4'],
71
+ declared: { types: ['static', 'test', 'analytics'], severity: 'hint' },
72
+ contexts: {
73
+ static: 'heuristic',
74
+ test: 'heuristic',
75
+ analytics: 'heuristic',
76
+ },
77
+ },
78
+ 'rfc6797/hsts-host-must-send-max-age-directive': {
79
+ covers: ['6.1.1/1'],
80
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
81
+ },
82
+ 'rfc6797/hsts-host-must-send-max-age-as-delta-seconds': {
83
+ covers: ['6.1.1/2'],
84
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
85
+ },
86
+ // 6.1.2/1 carries two claims: the directive is valueless (a syntax
87
+ // requirement), and it is OPTIONAL (a permission, checkable at `hint`).
88
+ 'rfc6797/hsts-host-must-send-include-subdomains-without-value': {
89
+ covers: ['6.1.2/1'],
90
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
91
+ },
92
+ 'rfc6797/hsts-host-may-assert-include-subdomains': {
93
+ covers: ['6.1.2/1'],
94
+ declared: { types: ['static', 'test', 'analytics'], severity: 'hint' },
95
+ },
96
+ // §7 — the server processing model.
97
+ // 7.1/1's other two clauses: the grammar is the syntax rule's above, and
98
+ // its conditional SHOULD — send the header — binds only a host that has
99
+ // chosen to be an HSTS Host, so it is carried by the presence convention,
100
+ // which covers no unit.
101
+ 'rfc6797/hsts-host-must-send-only-one-sts-header': {
102
+ covers: ['7.1/1'],
103
+ declared: { types: ['test', 'analytics'], severity: 'error' },
104
+ contexts: {
105
+ static: {
106
+ verdict: 'impossible',
107
+ reason: 'not-representable',
108
+ note: 'An API description declares response headers as a map keyed by name, so it cannot declare two Strict-Transport-Security field lines in one response.',
109
+ },
110
+ },
111
+ },
112
+ // A MAY is checkable at `hint`: the header is sent, or the mechanism
113
+ // goes unused.
114
+ 'rfc6797/server-may-establish-hsts-over-secure-transport': {
115
+ covers: ['7.1/2'],
116
+ declared: { types: ['static', 'test', 'analytics'], severity: 'hint' },
117
+ },
118
+ 'rfc6797/sts-header-inclusion-is-should-to-accommodate-caches': {
119
+ covers: ['7.1/3'],
120
+ declared: { types: ['informational'], severity: 'hint' },
121
+ },
122
+ // The SHOULD binds an HSTS Host, and whether the host behind a plain-http
123
+ // listener has chosen to be one is in no exchange: heuristic everywhere.
124
+ 'rfc6797/hsts-host-should-redirect-insecure-requests-to-https': {
125
+ covers: ['7.2/1'],
126
+ declared: { types: ['static', 'test', 'analytics'], severity: 'warn' },
127
+ contexts: {
128
+ static: 'heuristic',
129
+ test: 'heuristic',
130
+ analytics: 'heuristic',
131
+ },
132
+ },
133
+ 'rfc6797/https-redirect-is-should-for-deployment-reasons': {
134
+ covers: ['7.2/2'],
135
+ declared: { types: ['informational'], severity: 'hint' },
136
+ },
137
+ // Exact, although it binds an HSTS Host: sending the header is what makes
138
+ // a host one, so the condition is met by the header the rule looks for.
139
+ 'rfc6797/hsts-host-must-not-send-sts-header-over-insecure-transport': {
140
+ covers: ['7.2/3'],
141
+ declared: { types: ['static', 'test', 'analytics'], severity: 'error' },
142
+ },
143
+ // The two convention twins: each asks of every server, exactly, what the
144
+ // RFC asks only of an HSTS Host, so neither covers a unit.
145
+ 'rfc6797/server-should-send-sts-header-over-secure-transport': {
146
+ covers: [],
147
+ declared: { types: ['static', 'test', 'analytics'], severity: 'off' },
148
+ },
149
+ 'rfc6797/server-should-redirect-insecure-requests-to-https': {
150
+ covers: [],
151
+ declared: { types: ['static', 'test', 'analytics'], severity: 'off' },
152
+ },
153
+ // §9.2 — the effective request URI.
154
+ 'rfc6797/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris': {
155
+ covers: ['9.2/1'],
156
+ declared: { types: ['informational'], severity: 'error' },
157
+ },
158
+ },
159
+ });
160
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type RuleSet } from '@thymian/core';
2
+ declare const rfc6797: RuleSet;
3
+ export default rfc6797;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AAiBvB,QAAA,MAAM,OAAO,EAAE,OAYd,CAAC;AAEF,eAAe,OAAO,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ import { deriveMinimalProfile, } from '@thymian/core';
2
+ import coverage from './coverage.js';
3
+ // The opinionated layer: every convention rule on, at the severity its own
4
+ // explanation argues for. Each convention asks of every server, exactly, what
5
+ // RFC 6797 asks only of a host that has chosen to be an HSTS Host, which no
6
+ // exchange shows; each replaces the RFC rule that reports the same wire fact,
7
+ // so one response is reported once. The presence convention replaces 7.1's
8
+ // MAY `hint`, the redirect convention replaces 7.2's heuristic rule.
9
+ const recommended = {
10
+ 'rfc6797/server-should-send-sts-header-over-secure-transport': 'error',
11
+ 'rfc6797/server-may-establish-hsts-over-secure-transport': 'off',
12
+ 'rfc6797/server-should-redirect-insecure-requests-to-https': 'error',
13
+ 'rfc6797/hsts-host-should-redirect-insecure-requests-to-https': 'off',
14
+ };
15
+ const rfc6797 = {
16
+ name: 'rfc6797',
17
+ url: 'https://www.rfc-editor.org/rfc/rfc6797.html',
18
+ pattern: 'rules/**/*.rule.js',
19
+ profiles: {
20
+ recommended,
21
+ // Source fidelity: every rule at its shipped severity, which follows
22
+ // RFC 6797's keywords; convention rules stay off.
23
+ strict: {},
24
+ minimal: deriveMinimalProfile(coverage),
25
+ },
26
+ coverage,
27
+ };
28
+ export default rfc6797;
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAGrB,MAAM,eAAe,CAAC;AAEvB,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,qEAAqE;AACrE,MAAM,WAAW,GAAuB;IACtC,6DAA6D,EAAE,OAAO;IACtE,yDAAyD,EAAE,KAAK;IAChE,2DAA2D,EAAE,OAAO;IACpE,8DAA8D,EAAE,KAAK;CACtE,CAAC;AAEF,MAAM,OAAO,GAAY;IACvB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,6CAA6C;IAClD,OAAO,EAAE,oBAAoB;IAC7B,QAAQ,EAAE;QACR,WAAW;QACX,qEAAqE;QACrE,kDAAkD;QAClD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC;KACxC;IACD,QAAQ;CACT,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.ts"],"names":[],"mappings":";AAEA,wBAqBU"}
@@ -0,0 +1,12 @@
1
+ import { httpRule } from '@thymian/core';
2
+ export default httpRule('rfc6797/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris')
3
+ .severity('error')
4
+ .type('informational', 'peer-not-observable', 'The comparison happens inside whichever party compares two effective request URIs; neither URI, nor the outcome of comparing them, appears in any message. A redirect Location built from the effective request URI (§7.2) is checked by hsts-host-should-redirect-insecure-requests-to-https.')
5
+ .tags('security:transport')
6
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-9.2')
7
+ .description('Effective request URIs are compared using the rules described in [RFC2616] Section 3.2.3, except that empty path components MUST NOT be treated as equivalent to an absolute path of "/".')
8
+ .summary('HSTS Host must not treat an empty path as "/" when comparing effective request URIs.')
9
+ .explanation('Under RFC 2616\'s comparison rules an empty path and "/" name the same resource; RFC 6797 keeps them apart when effective request URIs are compared. The distinction lives inside the party that does the comparing and never shows on the wire, so this rule documents the requirement rather than checking it.')
10
+ .appliesTo('server')
11
+ .done();
12
+ //# sourceMappingURL=hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.js","sourceRoot":"","sources":["../../../src/rules/effective-request-uri/hsts-host-must-not-treat-empty-path-as-slash-when-comparing-effective-request-uris.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,eAAe,QAAQ,CACrB,4FAA4F,CAC7F;KACE,QAAQ,CAAC,OAAO,CAAC;KACjB,IAAI,CACH,eAAe,EACf,qBAAqB,EACrB,gSAAgS,CACjS;KACA,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,2LAA2L,CAC5L;KACA,OAAO,CACN,sFAAsF,CACvF;KACA,WAAW,CACV,kTAAkT,CACnT;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=hsts-host-must-not-send-sts-header-over-insecure-transport.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-not-send-sts-header-over-insecure-transport.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.ts"],"names":[],"mappings":";AA+CA,wBAiBU"}
@@ -0,0 +1,39 @@
1
+ import { httpRule, protocol, } from '@thymian/core';
2
+ import { carriesHeader } from '../utils/headers.js';
3
+ import { violation } from '../utils/results.js';
4
+ import { STS_HEADER } from '../utils/sts-field-value.js';
5
+ import { isServerFallbackOrigin, serverFallbackSkip, } from '../utils/transport.js';
6
+ const NAME = 'rfc6797/hsts-host-must-not-send-sts-header-over-insecure-transport';
7
+ const MESSAGE = 'This response over non-secure transport (http) carries a Strict-Transport-Security header field. An HSTS Host MUST NOT include it in responses conveyed over non-secure transport.';
8
+ // Sending the header at all is what makes a host an HSTS Host (§5.1), so the
9
+ // condition in "An HSTS Host MUST NOT" is met by the very header this rule
10
+ // looks for: exact in every context, never heuristic. The common interface
11
+ // sees both facts — the scheme through its request filter, the header by
12
+ // name — so one function serves every context; only whether the server URL
13
+ // fallback is skipped differs. It is skipped only where a header is there to
14
+ // be judged: without one, the response conforms whatever the scheme.
15
+ function judgeTransport({ skipServerFallback, }) {
16
+ return (ctx) => ctx.validateCommonHttpTransactions(protocol('http'), (req, res, location) => {
17
+ if (!carriesHeader(res, STS_HEADER)) {
18
+ return [];
19
+ }
20
+ return skipServerFallback && isServerFallbackOrigin(req.origin)
21
+ ? [serverFallbackSkip(location, NAME)]
22
+ : [violation(location, MESSAGE)];
23
+ });
24
+ }
25
+ export default httpRule(NAME)
26
+ .severity('error')
27
+ .type('static', 'test', 'analytics')
28
+ .tags('security:transport')
29
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.2')
30
+ .description('An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport.')
31
+ .summary('HSTS Host must not send Strict-Transport-Security over plain HTTP.')
32
+ .explanation('Over plain HTTP an attacker on the network can add, remove or rewrite any header, so a Strict-Transport-Security header received that way proves nothing about the host — which is why user agents must ignore it (RFC 6797 §8.1). Sending it anyway protects nobody, and it signals a deployment that does not distinguish its secure and insecure listeners: the same configuration that sends the header over http is often the one that serves real content there instead of redirecting to https.')
33
+ .appliesTo('server')
34
+ // `static` and `test` carry the described origin, so both skip the
35
+ // fallback; recorded traffic in `analytics` is real, so it never does.
36
+ .rule(judgeTransport({ skipServerFallback: true }))
37
+ .overrideAnalyticsRule(judgeTransport({ skipServerFallback: false }))
38
+ .done();
39
+ //# sourceMappingURL=hsts-host-must-not-send-sts-header-over-insecure-transport.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-not-send-sts-header-over-insecure-transport.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-must-not-send-sts-header-over-insecure-transport.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,QAAQ,GAET,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAoB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,IAAI,GACR,oEAAoE,CAAC;AAEvE,MAAM,OAAO,GACX,oLAAoL,CAAC;AAEvL,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,yEAAyE;AACzE,2EAA2E;AAC3E,6EAA6E;AAC7E,qEAAqE;AACrE,SAAS,cAAc,CAAC,EACtB,kBAAkB,GAGnB;IACC,OAAO,CAAC,GAAG,EAAE,EAAE,CACb,GAAG,CAAC,8BAA8B,CAChC,QAAQ,CAAC,MAAM,CAAC,EAChB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;QACrB,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC;YACpC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,kBAAkB,IAAI,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC;YAC7D,CAAC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACrC,CAAC,CACF,CAAC;AACN,CAAC;AAED,eAAe,QAAQ,CAAC,IAAI,CAAC;KAC1B,QAAQ,CAAC,OAAO,CAAC;KACjB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC;KACnC,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,0GAA0G,CAC3G;KACA,OAAO,CAAC,oEAAoE,CAAC;KAC7E,WAAW,CACV,weAAwe,CACze;KACA,SAAS,CAAC,QAAQ,CAAC;IACpB,mEAAmE;IACnE,uEAAuE;KACtE,IAAI,CAAC,cAAc,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;KAClD,qBAAqB,CAAC,cAAc,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC;KACpE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=hsts-host-must-send-only-one-sts-header.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-send-only-one-sts-header.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.ts"],"names":[],"mappings":";AA6BA,wBAgBU"}
@@ -0,0 +1,35 @@
1
+ import { constant, httpRule } from '@thymian/core';
2
+ import { violation } from '../utils/results.js';
3
+ import { liveStsValues } from '../utils/sts-contexts.js';
4
+ // Sending the header is what makes a host an HSTS Host (§5.1), so the
5
+ // condition in "If an STS header field is included" is met by the very field
6
+ // lines this rule counts: exact, never heuristic. `constant(true)` as the
7
+ // candidate filter for the same reason as the value rules': `test` picks the
8
+ // requests it sends over the described transactions, and a server that adds
9
+ // a second field line where the description declares none is the case this
10
+ // rule exists for.
11
+ function checkLive(ctx) {
12
+ return ctx.validateHttpTransactions(constant(true), (_req, res, location) => {
13
+ const fieldLines = liveStsValues(res.headers);
14
+ return fieldLines.length > 1
15
+ ? [
16
+ violation(location, `This response carries ${fieldLines.length} Strict-Transport-Security header fields (${fieldLines.map((line) => `"${line}"`).join(', ')}). An HSTS Host MUST include only one; a UA processes only the first.`),
17
+ ]
18
+ : [];
19
+ });
20
+ }
21
+ // No `static`: an API description declares a response's headers as a map
22
+ // keyed by name, which cannot hold two field lines of one header (the
23
+ // coverage record's `not-representable` cell).
24
+ export default httpRule('rfc6797/hsts-host-must-send-only-one-sts-header')
25
+ .severity('error')
26
+ .type('test', 'analytics')
27
+ .tags('security:transport')
28
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.1')
29
+ .description('If an STS header field is included, the HSTS Host MUST include only one such header field.')
30
+ .summary('HSTS Host must send only one Strict-Transport-Security header field.')
31
+ .explanation('Two Strict-Transport-Security header fields in one response usually mean two layers — the application and a proxy or CDN in front of it — each adding their own. A browser processes only the first and ignores the rest (RFC 6797 §8.1), so which policy takes effect depends on header order, and the one the operator actually configured may be the one that is silently dropped.')
32
+ .appliesTo('server')
33
+ .rule(checkLive)
34
+ .done();
35
+ //# sourceMappingURL=hsts-host-must-send-only-one-sts-header.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-must-send-only-one-sts-header.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-must-send-only-one-sts-header.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,sEAAsE;AACtE,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,mBAAmB;AACnB,SAAS,SAAS,CAAC,GAAmB;IACpC,OAAO,GAAG,CAAC,wBAAwB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;QAC1E,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC;YAC1B,CAAC,CAAC;gBACE,SAAS,CACP,QAAQ,EACR,yBAAyB,UAAU,CAAC,MAAM,6CAA6C,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,uEAAuE,CAC/M;aACF;YACH,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,sEAAsE;AACtE,+CAA+C;AAC/C,eAAe,QAAQ,CAAC,iDAAiD,CAAC;KACvE,QAAQ,CAAC,OAAO,CAAC;KACjB,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC;KACzB,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,4FAA4F,CAC7F;KACA,OAAO,CACN,sEAAsE,CACvE;KACA,WAAW,CACV,uXAAuX,CACxX;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,CAAC,SAAS,CAAC;KACf,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=hsts-host-should-redirect-insecure-requests-to-https.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-should-redirect-insecure-requests-to-https.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.ts"],"names":[],"mappings":";AAcA,wBAkBU"}
@@ -0,0 +1,24 @@
1
+ import { httpRule } from '@thymian/core';
2
+ import { redirectRuleFns } from '../utils/redirect.js';
3
+ const NAME = 'rfc6797/hsts-host-should-redirect-insecure-requests-to-https';
4
+ const { lint, test, analytics } = redirectRuleFns(NAME);
5
+ // Heuristic in every context: the SHOULD binds an HSTS Host, and whether the
6
+ // host behind a plain-http listener has chosen to be one is in no exchange —
7
+ // a host that never opted into HSTS is not bound by §7.2. A heuristic rule is
8
+ // never promoted, so the
9
+ // `server-should-redirect-insecure-requests-to-https` convention rule asks
10
+ // the same of every server, exactly, and replaces this one in `recommended`.
11
+ export default httpRule(NAME)
12
+ .severity('warn')
13
+ .type('static', 'test', 'analytics')
14
+ .tags('security:transport')
15
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.2')
16
+ .description('If an HSTS Host receives an HTTP request message over a non-secure transport, it SHOULD send an HTTP response message containing a status code indicating a permanent redirect, such as status code 301, and a Location header field value containing either the HTTP request\'s original Effective Request URI altered as necessary to have a URI scheme of "https", or a URI generated according to local policy with a URI scheme of "https".')
17
+ .summary('HSTS Host should permanently redirect plain-HTTP requests to https.')
18
+ .explanation("A browser that has never seen a host's HSTS Policy still starts with plain HTTP, typically because a user typed the bare domain. Answering that request with a permanent redirect to https moves the user onto a secure connection, where the Strict-Transport-Security header can then be delivered. Serving content over HTTP instead keeps the user there, where any attacker on the network can read and rewrite the traffic; a temporary redirect (302, 307) moves the user too, but is followed again over HTTP on every visit.")
19
+ .appliesTo('server')
20
+ .overrideStaticRule(lint)
21
+ .overrideTest(test)
22
+ .overrideAnalyticsRule(analytics)
23
+ .done();
24
+ //# sourceMappingURL=hsts-host-should-redirect-insecure-requests-to-https.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-should-redirect-insecure-requests-to-https.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/hsts-host-should-redirect-insecure-requests-to-https.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,IAAI,GAAG,8DAA8D,CAAC;AAE5E,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;AAExD,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,yBAAyB;AACzB,2EAA2E;AAC3E,6EAA6E;AAC7E,eAAe,QAAQ,CAAC,IAAI,CAAC;KAC1B,QAAQ,CAAC,MAAM,CAAC;KAChB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC;KACnC,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,kbAAkb,CACnb;KACA,OAAO,CACN,qEAAqE,CACtE;KACA,WAAW,CACV,ugBAAugB,CACxgB;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,kBAAkB,CAAC,IAAI,CAAC;KACxB,YAAY,CAAC,IAAI,CAAC;KAClB,qBAAqB,CAAC,SAAS,CAAC;KAChC,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=https-redirect-is-should-for-deployment-reasons.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"https-redirect-is-should-for-deployment-reasons.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.ts"],"names":[],"mappings":";AAIA,wBAqBU"}
@@ -0,0 +1,14 @@
1
+ import { httpRule } from '@thymian/core';
2
+ // A NOTE the counting rule counts because it quotes a keyword to explain
3
+ // one: a unit, but nothing any message could conform to or violate.
4
+ export default httpRule('rfc6797/https-redirect-is-should-for-deployment-reasons')
5
+ .severity('hint')
6
+ .type('informational', 'nothing-to-check', 'A note explaining why the redirect before it is a SHOULD rather than a MUST; it states no requirement a message could meet or break. The redirect itself is checked by hsts-host-should-redirect-insecure-requests-to-https and, in the recommended profile, by the server-should-redirect-insecure-requests-to-https convention rule.')
7
+ .tags('security:transport')
8
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.2')
9
+ .description('NOTE: The above behavior is a "SHOULD" rather than a "MUST" due to: risks in server-side non-secure-to-secure redirects [OWASP-TLSGuide]; and site deployment characteristics. For example, a site that incorporates third-party components may not behave correctly when doing server-side non-secure-to-secure redirects in the case of being accessed over non-secure transport but does behave correctly when accessed uniformly over secure transport. The latter is the case given an HSTS-capable UA that has already noted the site as a Known HSTS Host (by whatever means, e.g., prior interaction or UA configuration).')
10
+ .summary('Redirecting plain-HTTP requests to https is a SHOULD for deployment reasons.')
11
+ .explanation("RFC 6797 leaves the redirect a SHOULD because a server-side redirect from http to https carries risks of its own, and because a site built from third-party components can break when redirected mid-visit although it works when reached over https from the start — which is how a browser that already knows the host's policy reaches it.")
12
+ .appliesTo('server')
13
+ .done();
14
+ //# sourceMappingURL=https-redirect-is-should-for-deployment-reasons.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"https-redirect-is-should-for-deployment-reasons.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/https-redirect-is-should-for-deployment-reasons.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,yEAAyE;AACzE,oEAAoE;AACpE,eAAe,QAAQ,CACrB,yDAAyD,CAC1D;KACE,QAAQ,CAAC,MAAM,CAAC;KAChB,IAAI,CACH,eAAe,EACf,kBAAkB,EAClB,wUAAwU,CACzU;KACA,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,omBAAomB,CACrmB;KACA,OAAO,CACN,8EAA8E,CAC/E;KACA,WAAW,CACV,+UAA+U,CAChV;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=server-may-establish-hsts-over-secure-transport.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-may-establish-hsts-over-secure-transport.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.ts"],"names":[],"mappings":";AAYA,wBAkBU"}
@@ -0,0 +1,19 @@
1
+ import { httpRule } from '@thymian/core';
2
+ import { stsPresenceRuleFn } from '../utils/sts-contexts.js';
3
+ const checkPresence = stsPresenceRuleFn('This response over secure transport (https) carries no Strict-Transport-Security header field. RFC 6797 lets a host establish HSTS by returning one; this response does not use it.');
4
+ // A MAY is checkable at `hint`: the finding is "the protocol offers this
5
+ // mechanism and it is not used", which claims no non-conformance. The
6
+ // pre-load list the same paragraph permits is in no exchange, so a host that
7
+ // relies on it alone is still hinted at here.
8
+ export default httpRule('rfc6797/server-may-establish-hsts-over-secure-transport')
9
+ .severity('hint')
10
+ .type('static', 'test', 'analytics')
11
+ .tags('security:transport')
12
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.1')
13
+ .description('Establishing a given host as a Known HSTS Host, in the context of a given UA, MAY be accomplished over HTTP, which is in turn running over secure transport, by correctly returning (per this specification) at least one valid STS header field to the UA. Other mechanisms, such as a client-side pre-loaded Known HSTS Host list, MAY also be used.')
14
+ .summary('Server may establish HSTS by sending Strict-Transport-Security over https.')
15
+ .explanation('Returning a Strict-Transport-Security header over https is how a host tells browsers to use only https from then on; a response without it gives the browser nothing to note. The pre-load lists RFC 6797 also mentions are not visible in any exchange. The server-should-send-sts-header-over-secure-transport convention rule asks for the header outright and replaces this hint in the recommended profile.')
16
+ .appliesTo('server')
17
+ .rule(checkPresence)
18
+ .done();
19
+ //# sourceMappingURL=server-may-establish-hsts-over-secure-transport.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-may-establish-hsts-over-secure-transport.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-may-establish-hsts-over-secure-transport.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,aAAa,GAAG,iBAAiB,CACrC,qLAAqL,CACtL,CAAC;AAEF,yEAAyE;AACzE,sEAAsE;AACtE,6EAA6E;AAC7E,8CAA8C;AAC9C,eAAe,QAAQ,CACrB,yDAAyD,CAC1D;KACE,QAAQ,CAAC,MAAM,CAAC;KAChB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC;KACnC,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,wVAAwV,CACzV;KACA,OAAO,CACN,4EAA4E,CAC7E;KACA,WAAW,CACV,kZAAkZ,CACnZ;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,CAAC,aAAa,CAAC;KACnB,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=server-should-redirect-insecure-requests-to-https.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-should-redirect-insecure-requests-to-https.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.ts"],"names":[],"mappings":";AAeA,wBAgBU"}
@@ -0,0 +1,25 @@
1
+ import { httpRule } from '@thymian/core';
2
+ import { redirectRuleFns } from '../utils/redirect.js';
3
+ const NAME = 'rfc6797/server-should-redirect-insecure-requests-to-https';
4
+ const { lint, test, analytics } = redirectRuleFns(NAME);
5
+ // A convention rule, the exact twin of
6
+ // `hsts-host-should-redirect-insecure-requests-to-https`: RFC 6797 asks for
7
+ // the redirect only from a host that has chosen to be an HSTS Host, which no
8
+ // exchange shows, so that rule is heuristic and can never be promoted.
9
+ // Asking it of every server drops the condition and makes the check exact,
10
+ // so this one ships `off`, covers no unit, and the `recommended` profile
11
+ // turns it on in the other's place.
12
+ export default httpRule(NAME)
13
+ .severity('off')
14
+ .type('static', 'test', 'analytics')
15
+ .tags('security:transport')
16
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.2')
17
+ .description('A server should answer every request over non-secure transport with a permanent redirect to the resource over https. RFC 6797 asks this only of an HSTS Host; this is a convention.')
18
+ .summary('Server should permanently redirect plain-HTTP requests to https.')
19
+ .explanation('RFC 6797 asks for this redirect only from a host that has already chosen to be an HSTS Host, and the recommended profile requires it of every server because a plain-HTTP request not answered by a permanent redirect — typically a typed bare domain on a first visit — is exactly the downgrade window HSTS exists to close, and the one place its header can never be delivered.')
20
+ .appliesTo('server')
21
+ .overrideStaticRule(lint)
22
+ .overrideTest(test)
23
+ .overrideAnalyticsRule(analytics)
24
+ .done();
25
+ //# sourceMappingURL=server-should-redirect-insecure-requests-to-https.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-should-redirect-insecure-requests-to-https.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-should-redirect-insecure-requests-to-https.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,IAAI,GAAG,2DAA2D,CAAC;AAEzE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;AAExD,uCAAuC;AACvC,4EAA4E;AAC5E,6EAA6E;AAC7E,uEAAuE;AACvE,2EAA2E;AAC3E,yEAAyE;AACzE,oCAAoC;AACpC,eAAe,QAAQ,CAAC,IAAI,CAAC;KAC1B,QAAQ,CAAC,KAAK,CAAC;KACf,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC;KACnC,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,qLAAqL,CACtL;KACA,OAAO,CAAC,kEAAkE,CAAC;KAC3E,WAAW,CACV,sXAAsX,CACvX;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,kBAAkB,CAAC,IAAI,CAAC;KACxB,YAAY,CAAC,IAAI,CAAC;KAClB,qBAAqB,CAAC,SAAS,CAAC;KAChC,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=server-should-send-sts-header-over-secure-transport.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-should-send-sts-header-over-secure-transport.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.ts"],"names":[],"mappings":";AAeA,wBAkBU"}
@@ -0,0 +1,22 @@
1
+ import { httpRule } from '@thymian/core';
2
+ import { stsPresenceRuleFn } from '../utils/sts-contexts.js';
3
+ const checkPresence = stsPresenceRuleFn('This response over secure transport (https) carries no Strict-Transport-Security header field, so it gives the browser no HSTS Policy to note or refresh.');
4
+ // A convention rule, the exact twin of 7.1's conditional SHOULD. RFC 6797
5
+ // permits establishing HSTS by returning the header (a MAY, checked at `hint`
6
+ // by `server-may-establish-hsts-over-secure-transport`) and asks it of every
7
+ // response only from a host that has already chosen to be an HSTS Host,
8
+ // which no single response shows. Asking it of every server drops the
9
+ // condition and makes the check exact, so this one ships `off`, covers no
10
+ // unit, and the `recommended` profile turns it on in the hint's place.
11
+ export default httpRule('rfc6797/server-should-send-sts-header-over-secure-transport')
12
+ .severity('off')
13
+ .type('static', 'test', 'analytics')
14
+ .tags('security:transport')
15
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.1')
16
+ .description('A server should include a Strict-Transport-Security header field in every response over secure transport. RFC 6797 does not require it of every server; this is a convention.')
17
+ .summary('Server should send Strict-Transport-Security in every response over https.')
18
+ .explanation("RFC 6797 only permits a host to establish HSTS by sending this header and asks it of every response only from a host that has already chosen to be an HSTS Host, and the recommended profile requires it of every server because, outside the browsers' pre-load lists, the header is the only way a browser learns the policy, so a response without it leaves every first visit, and every visit after the policy lapses, open to a downgrade to plain HTTP.")
19
+ .appliesTo('server')
20
+ .rule(checkPresence)
21
+ .done();
22
+ //# sourceMappingURL=server-should-send-sts-header-over-secure-transport.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-should-send-sts-header-over-secure-transport.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/server-should-send-sts-header-over-secure-transport.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,aAAa,GAAG,iBAAiB,CACrC,2JAA2J,CAC5J,CAAC;AAEF,0EAA0E;AAC1E,8EAA8E;AAC9E,6EAA6E;AAC7E,wEAAwE;AACxE,sEAAsE;AACtE,0EAA0E;AAC1E,uEAAuE;AACvE,eAAe,QAAQ,CACrB,6DAA6D,CAC9D;KACE,QAAQ,CAAC,KAAK,CAAC;KACf,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC;KACnC,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,+KAA+K,CAChL;KACA,OAAO,CACN,4EAA4E,CAC7E;KACA,WAAW,CACV,gcAAgc,CACjc;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,CAAC,aAAa,CAAC;KACnB,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=sts-header-inclusion-is-should-to-accommodate-caches.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sts-header-inclusion-is-should-to-accommodate-caches.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.ts"],"names":[],"mappings":";AAIA,wBAqBU"}
@@ -0,0 +1,14 @@
1
+ import { httpRule } from '@thymian/core';
2
+ // A NOTE the counting rule counts because it quotes a keyword to explain
3
+ // one: a unit, but nothing any message could conform to or violate.
4
+ export default httpRule('rfc6797/sts-header-inclusion-is-should-to-accommodate-caches')
5
+ .severity('hint')
6
+ .type('informational', 'nothing-to-check', 'A note explaining why the requirement before it is a SHOULD rather than a MUST; it states no requirement a message could meet or break. Sending the header is checked by server-may-establish-hsts-over-secure-transport and, in the recommended profile, by the server-should-send-sts-header-over-secure-transport convention rule.')
7
+ .tags('security:transport')
8
+ .url('https://www.rfc-editor.org/rfc/rfc6797.html#section-7.1')
9
+ .description('NOTE: Including the STS header field is stipulated as a "SHOULD" in order to accommodate various server- and network-side caches and load-balancing configurations where it may be difficult to uniformly emit STS header fields on behalf of a given HSTS Host.')
10
+ .summary('Sending Strict-Transport-Security is a SHOULD to accommodate caches and load balancers.')
11
+ .explanation('RFC 6797 asks for the header on every response over https without requiring it, because a cache or load balancer in front of the host may answer with responses the host itself never emitted. That is also why a missing header is worth reporting: the layer that drops it is usually one the operator configured and forgot.')
12
+ .appliesTo('server')
13
+ .done();
14
+ //# sourceMappingURL=sts-header-inclusion-is-should-to-accommodate-caches.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sts-header-inclusion-is-should-to-accommodate-caches.rule.js","sourceRoot":"","sources":["../../../src/rules/server-processing-model/sts-header-inclusion-is-should-to-accommodate-caches.rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,yEAAyE;AACzE,oEAAoE;AACpE,eAAe,QAAQ,CACrB,8DAA8D,CAC/D;KACE,QAAQ,CAAC,MAAM,CAAC;KAChB,IAAI,CACH,eAAe,EACf,kBAAkB,EAClB,uUAAuU,CACxU;KACA,IAAI,CAAC,oBAAoB,CAAC;KAC1B,GAAG,CAAC,yDAAyD,CAAC;KAC9D,WAAW,CACV,kQAAkQ,CACnQ;KACA,OAAO,CACN,yFAAyF,CAC1F;KACA,WAAW,CACV,iUAAiU,CAClU;KACA,SAAS,CAAC,QAAQ,CAAC;KACnB,IAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@thymian/core").Rule<Record<PropertyKey, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=hsts-host-may-assert-include-subdomains.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hsts-host-may-assert-include-subdomains.rule.d.ts","sourceRoot":"","sources":["../../../src/rules/syntax/hsts-host-may-assert-include-subdomains.rule.ts"],"names":[],"mappings":";AA0BA,wBAqBU"}