Skip to content

Commit bb0c103

Browse files
authored
Merge pull request #27 from soapbucket/adding-new-features
refactor: security_headers array format and session field rename
2 parents a222ebb + eee11fa commit bb0c103

19 files changed

Lines changed: 480 additions & 1001 deletions

docs/config.md

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Each key in `origins:` is a hostname. The value is an origin config object.
132132
| `request_modifiers` | []object | — | Request modification rules (see section 8) |
133133
| `response_modifiers` | []object | — | Response modification rules (see section 8) |
134134
| `forward_rules` | []object | — | Path-based routing rules (see section 9) |
135-
| `session_config` | object | | Session settings (see section 10) |
135+
| `session` | object | none | Session settings (see section 10) |
136136
| `error_pages` | []object | — | Custom error page definitions (see section 11) |
137137
| `variables` | object | — | Key-value variables for template use (see section 12) |
138138
| `secrets` | object | — | Secret references (see section 12) |
@@ -848,46 +848,42 @@ policies:
848848
| Field | Type | Default | Description |
849849
|---|---|---|---|
850850
| `type` | string | — | `"security_headers"` |
851-
| `strict_transport_security` | object | — | HSTS policy |
852-
| `content_security_policy` | object | — | CSP policy |
853-
| `x_frame_options` | object | — | X-Frame-Options |
854-
| `x_content_type_options` | object | — | X-Content-Type-Options |
855-
| `x_xss_protection` | object | — | X-XSS-Protection |
856-
| `referrer_policy` | object | — | Referrer-Policy |
857-
| `permissions_policy` | object | — | Permissions-Policy |
858-
859-
**HSTSConfig:**
860-
861-
| Field | Type | Default | Description |
862-
|---|---|---|---|
863-
| `enabled` | bool | false | Enable HSTS header |
864-
| `max_age` | int | 0 | `max-age` in seconds |
865-
| `include_subdomains` | bool | false | Include subdomains |
866-
| `preload` | bool | false | Include preload directive |
851+
| `headers` | []object | none | List of `{name, value}` response headers to set (HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-* etc.) |
852+
| `content_security_policy` | object | none | Advanced CSP block (nonce injection, report-only, per-route policies) |
867853

868854
**CSPConfig:**
869855

870856
| Field | Type | Default | Description |
871857
|---|---|---|---|
872-
| `enabled` | bool | false | Enable CSP header |
873-
| `policy` | string | `""` | Simple policy string |
858+
| `policy` | string | `""` | Base CSP policy string |
859+
| `enable_nonce` | bool | false | Inject per-request nonce in `script-src`/`style-src` |
874860
| `report_only` | bool | false | Use `Content-Security-Policy-Report-Only` |
875861
| `report_uri` | string | `""` | Violation report endpoint |
876-
| `directives` | object | | Structured CSP directives |
862+
| `dynamic_routes` | map | none | Route-prefix to override CSP policy |
877863

878864
```yaml
879865
policies:
880866
- type: security_headers
881-
strict_transport_security:
882-
enabled: true
883-
max_age: 31536000
884-
include_subdomains: true
885-
x_frame_options:
886-
enabled: true
887-
value: DENY
888-
x_content_type_options:
889-
enabled: true
890-
no_sniff: true
867+
headers:
868+
- name: Strict-Transport-Security
869+
value: "max-age=31536000; includeSubDomains"
870+
- name: X-Frame-Options
871+
value: DENY
872+
- name: X-Content-Type-Options
873+
value: nosniff
874+
- name: Referrer-Policy
875+
value: strict-origin-when-cross-origin
876+
- name: Permissions-Policy
877+
value: "camera=()"
878+
# Optional: detailed CSP block for nonce / dynamic routes only.
879+
content_security_policy:
880+
policy: "default-src 'self'"
881+
enable_nonce: false # true to inject per-request nonce in script-src/style-src
882+
report_only: false
883+
report_uri: ""
884+
# dynamic_routes:
885+
# "/admin":
886+
# policy: "default-src 'self' admin.example.com"
891887
```
892888

893889
### 5.7 `request_limiting` - Request Size Limiting
@@ -1309,14 +1305,14 @@ forward_rules:
13091305

13101306
---
13111307

1312-
## 10. Session Config (`session_config`)
1308+
## 10. Session Config (`session`)
13131309

13141310
| Field | Type | Default | Description |
13151311
|---|---|---|---|
13161312
| `disabled` | bool | false | Disable session management |
13171313
| `cookie_name` | string | `""` | Session cookie name |
1318-
| `cookie_max_age` | int | 0 | Session cookie max age in seconds |
1319-
| `cookie_same_site` | string | `""` | `Strict`, `Lax`, `None` |
1314+
| `max_age` | int | 0 | Session cookie max age in seconds |
1315+
| `same_site` | string | `""` | `Strict`, `Lax`, `None` |
13201316
| `disable_http_only` | bool | false | Remove HttpOnly flag from cookie |
13211317
| `allow_non_ssl` | bool | false | Allow sessions over HTTP |
13221318
| `enable_cookie_jar` | bool | false | Proxy backend Set-Cookie headers via session |

docs/configuration.md

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ origins:
105105
variables: { ... }
106106
vaults: { ... }
107107
secrets: { ... }
108-
session_config: { ... }
108+
session: { ... }
109109
events: [ ... ]
110110
cors: { ... }
111111
compression: { ... }
@@ -258,7 +258,7 @@ origins:
258258
variables: { ... } # Optional: template variables
259259
vaults: { ... } # Optional: secret vault backends
260260
secrets: { ... } # Optional: secret references
261-
session_config: { ... } # Optional: session/cookie settings
261+
session: { ... } # Optional: session/cookie settings
262262
on_load: [ ... ] # Optional: startup callbacks
263263
on_request: [ ... ] # Optional: per-request callbacks
264264
on_response: [ ... ] # Optional: post-response callbacks
@@ -982,35 +982,34 @@ Inject security headers into every response. Use this to harden browser security
982982
```yaml
983983
policies:
984984
- type: security_headers
985-
strict_transport_security:
986-
enabled: true
987-
max_age: 31536000
988-
include_subdomains: true
989-
preload: true
985+
headers:
986+
- name: Strict-Transport-Security
987+
value: "max-age=31536000; includeSubDomains; preload"
988+
- name: X-Frame-Options
989+
value: DENY
990+
- name: X-Content-Type-Options
991+
value: nosniff
992+
- name: Referrer-Policy
993+
value: strict-origin-when-cross-origin
994+
- name: Permissions-Policy
995+
value: "camera=(), microphone=(), geolocation=()"
996+
# Optional: detailed CSP block for nonce / dynamic routes only.
990997
content_security_policy:
991998
policy: "default-src 'self'; script-src 'self' https://cdn.example.com"
992-
x_frame_options:
993-
value: DENY
994-
x_content_type_options:
995-
enabled: true
996-
referrer_policy:
997-
value: strict-origin-when-cross-origin
998-
permissions_policy:
999-
policy: "camera=(), microphone=(), geolocation=()"
999+
enable_nonce: false # true to inject per-request nonce in script-src/style-src
1000+
report_only: false
1001+
report_uri: ""
1002+
# dynamic_routes:
1003+
# "/admin":
1004+
# policy: "default-src 'self' admin.example.com"
10001005
```
10011006

1007+
Use `headers` as a simple list of `{name, value}` pairs for any response header (HSTS, Cross-Origin-*, COEP/COOP/CORP, Referrer-Policy, Permissions-Policy, etc.). The optional `content_security_policy` block is for advanced CSP behavior only (per-request nonce injection, report-only mode, per-route overrides). For a plain CSP without nonce or dynamic routes, just add a `Content-Security-Policy` entry to `headers` directly.
1008+
10021009
| Field | Type | Default | Description |
10031010
|-------|------|---------|-------------|
1004-
| `strict_transport_security` | object | | HSTS settings (max_age, include_subdomains, preload) |
1005-
| `content_security_policy` | object | | CSP policy string |
1006-
| `x_frame_options` | object | | Frame embedding control (DENY, SAMEORIGIN) |
1007-
| `x_content_type_options` | object | | Prevent MIME type sniffing |
1008-
| `x_xss_protection` | object | | XSS filter (legacy browsers) |
1009-
| `referrer_policy` | object | | Controls Referer header |
1010-
| `permissions_policy` | object | | Feature permissions |
1011-
| `cross_origin_embedder_policy` | object | | COEP header |
1012-
| `cross_origin_opener_policy` | object | | COOP header |
1013-
| `cross_origin_resource_policy` | object | | CORP header |
1011+
| `headers` | []object | | List of `{name, value}` response headers to inject |
1012+
| `content_security_policy` | object | | Advanced CSP block (nonce injection, report-only, per-route policies) |
10141013

10151014
### csrf
10161015

@@ -1577,10 +1576,10 @@ Configure session behavior for an origin. Sessions are stored in encrypted cooki
15771576
```yaml
15781577
origins:
15791578
"app.example.com":
1580-
session_config:
1579+
session:
15811580
cookie_name: sb_session
1582-
cookie_max_age: 3600
1583-
cookie_same_site: Strict
1581+
max_age: 3600
1582+
same_site: Strict
15841583
disable_http_only: false
15851584
allow_non_ssl: false
15861585
enable_cookie_jar: true
@@ -1594,8 +1593,8 @@ origins:
15941593
|-------|------|---------|-------------|
15951594
| `disabled` | bool | false | Disable sessions entirely |
15961595
| `cookie_name` | string | sb_session | Session cookie name |
1597-
| `cookie_max_age` | int | 3600 | Cookie lifetime in seconds |
1598-
| `cookie_same_site` | string | Lax | SameSite attribute (Strict, Lax, None) |
1596+
| `max_age` | int | 3600 | Cookie lifetime in seconds |
1597+
| `same_site` | string | Lax | SameSite attribute (Strict, Lax, None) |
15991598
| `disable_http_only` | bool | false | If true, cookie is accessible to JavaScript |
16001599
| `allow_non_ssl` | bool | false | Allow sessions over HTTP (not just HTTPS) |
16011600
| `enable_cookie_jar` | bool | false | Store backend cookies in the session |
@@ -1905,7 +1904,7 @@ origins:
19051904
variables: { ... }
19061905
vaults: { ... }
19071906
secrets: { ... }
1908-
session_config: { ... }
1907+
session: { ... }
19091908
events: [ ... ]
19101909
cors: { ... }
19111910
compression: { ... }

docs/features.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -693,26 +693,26 @@ Inject security-oriented HTTP response headers.
693693
```yaml
694694
policies:
695695
- type: security_headers
696-
strict_transport_security:
697-
enabled: true
698-
max_age: 31536000
699-
include_subdomains: true
700-
preload: true
696+
headers:
697+
- name: Strict-Transport-Security
698+
value: "max-age=31536000; includeSubDomains; preload"
699+
- name: X-Frame-Options
700+
value: DENY
701+
- name: X-Content-Type-Options
702+
value: nosniff
703+
- name: Referrer-Policy
704+
value: strict-origin-when-cross-origin
705+
- name: Permissions-Policy
706+
value: "camera=()"
707+
# Optional: detailed CSP block for nonce / dynamic routes only.
701708
content_security_policy:
702-
enabled: true
703-
directives:
704-
default_src: ["'self'"]
705-
script_src: ["'self'", "'nonce-{generated}'"]
706-
connect_src: ["'self'", "https://api.test.sbproxy.dev"]
707-
x_frame_options:
708-
enabled: true
709-
value: DENY
710-
x_content_type_options:
711-
enabled: true
712-
no_sniff: true
713-
referrer_policy:
714-
enabled: true
715-
policy: strict-origin-when-cross-origin
709+
policy: "default-src 'self'; script-src 'self' 'nonce-{generated}'; connect-src 'self' https://api.test.sbproxy.dev"
710+
enable_nonce: true # true to inject per-request nonce in script-src/style-src
711+
report_only: false
712+
report_uri: ""
713+
# dynamic_routes:
714+
# "/admin":
715+
# policy: "default-src 'self' admin.example.com"
716716
```
717717

718718
### Request Limiting
@@ -1276,10 +1276,10 @@ error_pages:
12761276
sbproxy maintains a session layer for cookie-based state:
12771277

12781278
```yaml
1279-
session_config:
1279+
session:
12801280
cookie_name: _sb_session
1281-
cookie_max_age: 3600 # 1 hour
1282-
cookie_same_site: Lax
1281+
max_age: 3600 # 1 hour
1282+
same_site: Lax
12831283
disable_http_only: false # HttpOnly enabled by default
12841284
allow_non_ssl: false # Require HTTPS for session cookies
12851285
enable_cookie_jar: true # Proxy backend Set-Cookie via session
@@ -1307,7 +1307,7 @@ on_request:
13071307
cache_duration: 60s
13081308
13091309
# Session start callback
1310-
session_config:
1310+
session:
13111311
on_session_start:
13121312
- url: https://analytics.example.com/events
13131313
method: POST

examples/13-security-headers.yml

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -57,43 +57,32 @@ origins:
5757

5858
policies:
5959
# --- Security headers policy ---
60+
# Canonical format: `headers` is an array of name/value pairs. The
61+
# optional `content_security_policy` block is used only when you need
62+
# per-request nonce injection or per-URL-prefix policies.
6063
- type: security_headers
64+
headers:
65+
- name: Strict-Transport-Security
66+
value: "max-age=31536000; includeSubDomains"
67+
- name: X-Frame-Options
68+
value: SAMEORIGIN
69+
- name: X-Content-Type-Options
70+
value: nosniff
71+
- name: Referrer-Policy
72+
value: strict-origin-when-cross-origin
73+
- name: Permissions-Policy
74+
value: "camera=(), microphone=(), geolocation=()"
6175

62-
# HTTP Strict Transport Security (HSTS) - RFC 6797
63-
strict_transport_security:
64-
enabled: true
65-
max_age: 31536000 # 1 year in seconds
66-
include_subdomains: true # Apply to all subdomains
67-
preload: false # Add to browser preload list (use with caution)
68-
69-
# Content Security Policy (CSP)
76+
# Advanced CSP block. Leave this out for a simple static policy and
77+
# put `Content-Security-Policy` in the `headers:` array instead.
7078
content_security_policy:
71-
enabled: true
7279
policy: "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'"
80+
enable_nonce: false # true to inject a per-request nonce
7381
report_only: false # true = log violations but don't block
74-
75-
# X-Frame-Options: prevent clickjacking
76-
x_frame_options:
77-
enabled: true
78-
value: SAMEORIGIN # "DENY", "SAMEORIGIN", or "ALLOW-FROM <uri>"
79-
80-
# X-Content-Type-Options: prevent MIME sniffing
81-
x_content_type_options:
82-
enabled: true
83-
no_sniff: true
84-
85-
# Referrer-Policy: control how much referrer info is sent
86-
referrer_policy:
87-
enabled: true
88-
policy: strict-origin-when-cross-origin
89-
90-
# Permissions-Policy: control browser feature access
91-
permissions_policy:
92-
enabled: true
93-
features:
94-
camera: "()" # Disallow camera access
95-
microphone: "()" # Disallow microphone access
96-
geolocation: "()" # Disallow geolocation
82+
# report_uri: "/csp-report" # optional report destination
83+
# dynamic_routes:
84+
# "/admin":
85+
# policy: "default-src 'self' admin.example.com"
9786

9887
# --- IP filtering policy ---
9988
- type: ip_filtering

examples/16-full-production.yml

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,22 +93,17 @@ origins:
9393

9494
# Security headers
9595
- type: security_headers
96-
strict_transport_security:
97-
enabled: true
98-
max_age: 31536000 # 1 year
99-
include_subdomains: true
100-
content_security_policy:
101-
enabled: true
102-
policy: "default-src 'self'; connect-src 'self' https://api.example.com"
103-
x_frame_options:
104-
enabled: true
105-
value: DENY # Never render in a frame
106-
x_content_type_options:
107-
enabled: true
108-
no_sniff: true
109-
referrer_policy:
110-
enabled: true
111-
policy: strict-origin-when-cross-origin
96+
headers:
97+
- name: Strict-Transport-Security
98+
value: "max-age=31536000; includeSubDomains"
99+
- name: Content-Security-Policy
100+
value: "default-src 'self'; connect-src 'self' https://api.example.com"
101+
- name: X-Frame-Options
102+
value: DENY # Never render in a frame
103+
- name: X-Content-Type-Options
104+
value: nosniff
105+
- name: Referrer-Policy
106+
value: strict-origin-when-cross-origin
112107

113108
# --- Response caching ---
114109
response_cache:

internal/config/callback_template_e2e_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ func TestCallbackTemplateVariables_E2EConfig_Session(t *testing.T) {
107107
"id": "lua-callback-session",
108108
"hostname": "lua-callback-session.test",
109109
"workspace_id": "test-workspace",
110-
"session_config": {
110+
"session": {
111111
"enabled": true,
112112
"cookie_name": "_sb.session",
113-
"cookie_max_age": 3600,
113+
"max_age": 3600,
114114
"callbacks": [
115115
{
116116
"type": "http",

0 commit comments

Comments
 (0)