mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 08:46:58 +08:00
Merge branch 'owasp-headers' into 'master'
Owasp headers See merge request openconnect/ocserv!263
This commit is contained in:
@@ -438,6 +438,12 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, unsig
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = add_owasp_headers(ws);
|
||||
if (ret < 0) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = cstp_puts(ws, "\r\n");
|
||||
if (ret < 0) {
|
||||
ret = -1;
|
||||
@@ -1089,6 +1095,12 @@ int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret =
|
||||
add_owasp_headers(ws);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef ANYCONNECT_CLIENT_COMPAT
|
||||
if (WSCONFIG(ws)->xml_config_file) {
|
||||
ret =
|
||||
|
||||
@@ -58,6 +58,7 @@ static int send_headers(worker_st *ws, unsigned http_ver, const char *content_ty
|
||||
cstp_printf(ws, "Content-Type: %s\r\n", content_type) < 0 ||
|
||||
cstp_puts (ws, "X-Transcend-Version: 1\r\n") < 0 ||
|
||||
cstp_printf(ws, "Content-Length: %u\r\n", content_length) < 0 ||
|
||||
add_owasp_headers(ws) < 0 ||
|
||||
cstp_puts (ws, "\r\n") < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
@@ -863,3 +863,28 @@ void http_req_deinit(worker_st * ws)
|
||||
ws->req.body = NULL;
|
||||
}
|
||||
|
||||
/* add_owasp_headers:
|
||||
* @ws: an initialized worker structure
|
||||
*
|
||||
* This function adds the OWASP default headers
|
||||
* There are security tools that flag the server as a security risk.
|
||||
* These are added to help users comply with security best practices.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -273,6 +273,11 @@ int post_kkdcp_handler(worker_st *ws, unsigned http_ver)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = add_owasp_headers(ws);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = cstp_puts(ws, "\r\n");
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
|
||||
@@ -1931,6 +1931,9 @@ static int connect_handler(worker_st * ws)
|
||||
ret = cstp_puts(ws, "HTTP/1.1 200 CONNECTED\r\n");
|
||||
SEND_ERR(ret);
|
||||
|
||||
ret = add_owasp_headers(ws);
|
||||
SEND_ERR(ret);
|
||||
|
||||
ret = cstp_puts(ws, "X-CSTP-Version: 1\r\n");
|
||||
SEND_ERR(ret);
|
||||
|
||||
|
||||
@@ -422,6 +422,8 @@ int parse_proxy_proto_header(struct worker_st *ws, int fd);
|
||||
|
||||
void cookie_authenticate_or_exit(worker_st *ws);
|
||||
|
||||
int add_owasp_headers(worker_st * ws);
|
||||
|
||||
/* after that time (secs) of inactivity in the UDP part, connection switches to
|
||||
* TCP (if activity occurs there).
|
||||
*/
|
||||
|
||||
@@ -180,6 +180,7 @@ check_PROGRAMS += gen_oidc_test_data
|
||||
dist_check_SCRIPTS += test-oidc
|
||||
endif
|
||||
|
||||
dist_check_SCRIPTS += test-owasp-headers
|
||||
|
||||
dist_check_SCRIPTS += test-replay
|
||||
|
||||
|
||||
115
tests/test-owasp-headers
Executable file
115
tests/test-owasp-headers
Executable file
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2021 Microsoft Corporation
|
||||
#
|
||||
# This file is part of ocserv.
|
||||
#
|
||||
# ocserv is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
# ocserv is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GnuTLS; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
SERV="${SERV:-../src/ocserv}"
|
||||
srcdir=${srcdir:-.}
|
||||
NO_NEED_ROOT=1
|
||||
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
eval "${GETPORT}"
|
||||
|
||||
echo "Testing ocserv owasp headers... "
|
||||
|
||||
update_config test-user-cert.config
|
||||
launch_simple_sr_server -d 1 -f -c ${CONFIG}
|
||||
PID=$!
|
||||
|
||||
wait_server $PID
|
||||
|
||||
function CheckHeaders
|
||||
{
|
||||
[[ "$1" =~ .*"Strict-Transport-Security".* ]] || fail $PID "Missing HTTP header (Strict-Transport-Security)"
|
||||
[[ "$1" =~ .*"X-Frame-Options".* ]] || fail $PID "Missing HTTP header (X-Frame-Options)"
|
||||
[[ "$1" =~ .*"X-Content-Type-Options".* ]] || fail $PID "Missing HTTP header (X-Content-Type-Options)"
|
||||
[[ "$1" =~ .*"Content-Security-Policy".* ]] || fail $PID "Missing HTTP header (Content-Security-Policy)"
|
||||
[[ "$1" =~ .*"X-Permitted-Cross-Domain-Policies".* ]] || fail $PID "Missing HTTP header (X-Permitted-Cross-Domain-Policies)"
|
||||
[[ "$1" =~ .*"Referrer-Policy".* ]] || fail $PID "Missing HTTP header (Referrer-Policy)"
|
||||
[[ "$1" =~ .*"Clear-Site-Data".* ]] || fail $PID "Missing HTTP header (Clear-Site-Data)"
|
||||
[[ "$1" =~ .*"Cross-Origin-Embedder-Policy".* ]] || fail $PID "Missing HTTP header (Cross-Origin-Embedder-Policy)"
|
||||
[[ "$1" =~ .*"Cross-Origin-Opener-Policy".* ]] || fail $PID "Missing HTTP header (Cross-Origin-Opener-Policy)"
|
||||
[[ "$1" =~ .*"Cross-Origin-Resource-Policy".* ]] || fail $PID "Missing HTTP header (Cross-Origin-Resource-Policy)"
|
||||
[[ "$1" =~ .*"X-XSS-Protection".* ]] || fail $PID "Missing HTTP header (X-XSS-Protection)"
|
||||
|
||||
while IFS=':' read name value; do
|
||||
case "$name" in
|
||||
Strict-Transport-Security)
|
||||
[[ "$value" =~ "max-age=31536000 ; includeSubDomains" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
X-Frame-Options)
|
||||
[[ "$value" =~ "deny" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
X-Content-Type-Options)
|
||||
[[ "$value" =~ "nosniff" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Content-Security-Policy)
|
||||
[[ "$value" =~ "default-src 'none'" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
X-Permitted-Cross-Domain-Policies)
|
||||
[[ "$value" =~ "none" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Referrer-Policy)
|
||||
[[ "$value" =~ "no-referrer" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Clear-Site-Data)
|
||||
[[ "$value" =~ "\"cache\",\"cookies\",\"storage\"" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Cross-Origin-Embedder-Policy)
|
||||
[[ "$value" =~ "require-corp" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Cross-Origin-Opener-Policy)
|
||||
[[ "$value" =~ "same-origin" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
Cross-Origin-Resource-Policy)
|
||||
[[ "$value" =~ "same-origin" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
X-XSS-Protection)
|
||||
[[ "$value" =~ "0" ]] || fail $PID "Unexpected HTTP header value ($name: $value)";;
|
||||
esac
|
||||
done < <(echo "$1")
|
||||
}
|
||||
|
||||
echo -n "Testing / ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/ --insecure)
|
||||
CheckHeaders "$results"
|
||||
|
||||
echo -n "Testing /auth ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/auth --insecure)
|
||||
CheckHeaders "$results"
|
||||
|
||||
echo -n "Testing /VPN ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/VPN --insecure)
|
||||
CheckHeaders "$results"
|
||||
echo "ok"
|
||||
|
||||
echo -n "Testing /cert.pem ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/cert.pem --insecure)
|
||||
CheckHeaders "$results"
|
||||
echo "ok"
|
||||
|
||||
echo -n "Testing /cert.cer ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/cert.cer --insecure)
|
||||
CheckHeaders "$results"
|
||||
echo "ok"
|
||||
|
||||
echo -n "Testing /ca.pem ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/ca.pem --insecure)
|
||||
CheckHeaders "$results"
|
||||
echo "ok"
|
||||
|
||||
echo -n "Testing /ca.cer ... "
|
||||
results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/ca.cer --insecure)
|
||||
CheckHeaders "$results"
|
||||
echo "ok"
|
||||
|
||||
|
||||
cleanup
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user