File: 0004-Allow-HTTP-headers-to-be-configurable.patch

package info (click to toggle)
ocserv 1.1.6-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 7,484 kB
  • sloc: ansic: 44,469; sh: 11,205; makefile: 371; xml: 29
file content (146 lines) | stat: -rw-r--r-- 6,586 bytes parent folder | download
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
From: Tara Mallesh <taramallesh@microsoft.com>
Date: Mon, 14 Mar 2022 05:25:11 +0000
Subject: Allow HTTP headers to be configurable

---
 doc/sample.config        | 15 +++++++++++++++
 src/config.c             |  6 ++++++
 src/vpn.h                |  4 ++++
 src/worker-http.c        | 22 ++++++++--------------
 tests/test-owasp-headers | 20 ++++++++++++++++++--
 5 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/doc/sample.config b/doc/sample.config
index 0e33484..2fb1985 100644
--- a/doc/sample.config
+++ b/doc/sample.config
@@ -734,3 +734,18 @@ ipv4-network = 192.168.2.0
 ipv4-netmask = 255.255.255.0
 
 cert-user-oid = 0.9.2342.19200300.100.1.1
+
+# HTTP headers
+included-http-headers = Strict-Transport-Security: max-age=31536000 ; includeSubDomains
+included-http-headers = X-Frame-Options: deny
+included-http-headers = X-Content-Type-Options: nosniff
+included-http-headers = Content-Security-Policy: default-src 'none'
+included-http-headers = X-Permitted-Cross-Domain-Policies: none
+included-http-headers = Referrer-Policy: no-referrer
+included-http-headers = Clear-Site-Data: "cache","cookies","storage"
+included-http-headers = Cross-Origin-Embedder-Policy: require-corp
+included-http-headers = Cross-Origin-Opener-Policy: same-origin
+included-http-headers = Cross-Origin-Resource-Policy: same-origin
+included-http-headers = X-XSS-Protection: 0
+included-http-headers = Pragma: no-cache
+included-http-headers = Cache-control: no-store, no-cache
diff --git a/src/config.c b/src/config.c
index d8e1a01..7195d07 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1078,6 +1078,12 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co
 		READ_MULTI_LINE(config->custom_header, config->custom_header_size);
 	} else if (strcmp(name, "split-dns") == 0) {
 		READ_MULTI_LINE(config->split_dns, config->split_dns_size);
+	}  else if (strcmp(name, "included-http-headers") == 0) {
+		// Don't use sanitized input since http header values can contain optional trailing blanks and double quotes
+		if (_add_multi_line_val(pool, &(config->included_http_headers), &(config->included_http_headers_size), _value) < 0) {
+			fprintf(stderr, ERRSTR"memory\n");
+			exit(1);
+		}
 	} else if (strcmp(name, "route") == 0) {
 		READ_MULTI_LINE(config->network.routes, config->network.routes_size);
 	} else if (strcmp(name, "no-route") == 0) {
diff --git a/src/vpn.h b/src/vpn.h
index 3b737ab..3e09987 100644
--- a/src/vpn.h
+++ b/src/vpn.h
@@ -259,6 +259,10 @@ struct cfg_st {
 	char **split_dns;
 	size_t split_dns_size;;
 
+	/* http headers to include */
+	char **included_http_headers;
+	size_t included_http_headers_size;
+
 	unsigned int append_routes; /* whether to append global routes to per-user config */
 	unsigned restrict_user_to_routes; /* whether the firewall script will be run for the user */
 	unsigned deny_roaming; /* whether a cookie is restricted to a single IP */
diff --git a/src/worker-http.c b/src/worker-http.c
index 4294119..7049106 100644
--- a/src/worker-http.c
+++ b/src/worker-http.c
@@ -873,21 +873,15 @@ void http_req_deinit(worker_st * ws)
  */
 int add_owasp_headers(worker_st * ws)
 {
-	if (cstp_puts(ws, "Strict-Transport-Security: max-age=31536000 ; includeSubDomains\r\n") < 0 ||
-		cstp_puts(ws, "X-Frame-Options: deny\r\n") < 0 ||
-		cstp_puts(ws, "X-Content-Type-Options: nosniff\r\n") < 0 ||
-		cstp_puts(ws, "Content-Security-Policy: default-src \'none\'\r\n") < 0 ||
-		cstp_puts(ws, "X-Permitted-Cross-Domain-Policies: none\r\n") < 0 ||
-		cstp_puts(ws, "Referrer-Policy: no-referrer\r\n") < 0 ||
-		cstp_puts(ws, "Clear-Site-Data: \"cache\",\"cookies\",\"storage\"\r\n") < 0 ||
-		cstp_puts(ws, "Cross-Origin-Embedder-Policy: require-corp\r\n") < 0 ||
-		cstp_puts(ws, "Cross-Origin-Opener-Policy: same-origin\r\n") < 0 ||
-		cstp_puts(ws, "Cross-Origin-Resource-Policy: same-origin\r\n") < 0 ||
-		cstp_puts(ws, "X-XSS-Protection: 0\r\n") < 0 ||
-		cstp_puts(ws, "Pragma: no-cache\r\n") < 0 ||
-		cstp_puts(ws, "Cache-control: no-store\r\n") < 0)
+	unsigned i;
+
+	for(i=0; i < GETCONFIG(ws)->included_http_headers_size; i++)
 	{
-		return -1;
+		if (cstp_printf(ws, "%s", GETCONFIG(ws)->included_http_headers[i]) < 0 ||
+		    cstp_puts(ws, "\r\n") < 0)
+		{
+			return -1;
+		}
 	}
 	return 0;
 }
diff --git a/tests/test-owasp-headers b/tests/test-owasp-headers
index 3c2d958..ed9cedf 100755
--- a/tests/test-owasp-headers
+++ b/tests/test-owasp-headers
@@ -29,6 +29,22 @@ eval "${GETPORT}"
 echo "Testing ocserv owasp headers... "
 
 update_config test-user-cert.config
+
+# Add HTTP headers to the config file
+echo "included-http-headers = Strict-Transport-Security: max-age=31536000 ; includeSubDomains" >> ${CONFIG}
+echo "included-http-headers = X-Frame-Options: deny" >> ${CONFIG}
+echo "included-http-headers = X-Content-Type-Options: nosniff" >> ${CONFIG}
+echo "included-http-headers = Content-Security-Policy: default-src \'none\'" >> ${CONFIG}
+echo "included-http-headers = X-Permitted-Cross-Domain-Policies: none" >> ${CONFIG}
+echo "included-http-headers = Referrer-Policy: no-referrer" >> ${CONFIG}
+echo "included-http-headers = Clear-Site-Data: \"cache\",\"cookies\",\"storage\"" >> ${CONFIG}
+echo "included-http-headers = Cross-Origin-Embedder-Policy: require-corp" >> ${CONFIG}
+echo "included-http-headers = Cross-Origin-Opener-Policy: same-origin" >> ${CONFIG}
+echo "included-http-headers = Cross-Origin-Resource-Policy: same-origin" >> ${CONFIG}
+echo "included-http-headers = X-XSS-Protection: 0" >> ${CONFIG}
+echo "included-http-headers = Pragma: no-cache" >> ${CONFIG}
+echo "included-http-headers = Cache-control: no-cache, no-store" >> ${CONFIG}
+
 launch_simple_sr_server -d 1 -f -c ${CONFIG}
 PID=$!
 
@@ -49,7 +65,7 @@ function CheckHeaders
     [[ "$1" =~ .*"X-XSS-Protection".* ]] || fail $PID "Missing HTTP header (X-XSS-Protection)"
     [[ "$1" =~ .*"Pragma".* ]] || fail $PID "Missing HTTP header (Pragma)"
     [[ "$1" =~ .*"Cache-control".* ]] || fail $PID "Missing HTTP header (Cache-control)"
-
+    
 	while IFS=':' read name value; do
         case "$name" in
         Strict-Transport-Security)
@@ -77,7 +93,7 @@ function CheckHeaders
         Pragma)
             [[ "$value" =~ "no-cache" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
         Cache-control)
-            [[ "$value" =~ "no-store" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;    
+            [[ "$value" =~ "no-cache, no-store" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
         esac
 	done < <(echo "$1")
 }