mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-08-09 09:51:49 +08:00
worker: harden HTTP request header size limits
Bound memory growth in the worker for unauthenticated connections by enforcing HTTP headers limit in addition to HTTP body limit. Resolves: #712 Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2026 Nikos Mavrogiannopoulos
|
||||
#
|
||||
# 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 HTTP body and header size limits..."
|
||||
|
||||
update_config test-user-cert.config
|
||||
launch_simple_sr_server -d 1 -f -c ${CONFIG}
|
||||
PID=$!
|
||||
wait_server $PID
|
||||
|
||||
BODY_LIMIT=$((256 * 1024))
|
||||
HDR_LIMIT=$((16 * 1024))
|
||||
HDRFILE=test-http-limits.$$.tmp
|
||||
CURL_OUT=test-http-limits.$$.curl
|
||||
|
||||
# Run a POST via socket_wrapper; print HTTP status code to stdout.
|
||||
# Returns curl's exit code (28 = timeout, 52 = empty reply, 0 = got response).
|
||||
curl_post() {
|
||||
LD_PRELOAD=libsocket_wrapper.so \
|
||||
curl --silent --insecure --max-time 10 --user-agent "AnyConnect" \
|
||||
--write-out "%{http_code}" \
|
||||
"$@" -o "$CURL_OUT"
|
||||
}
|
||||
|
||||
echo -n "Testing body within limit (${BODY_LIMIT} bytes)... "
|
||||
http_code=$(head -c ${BODY_LIMIT} /dev/zero | \
|
||||
curl_post -X POST https://$ADDRESS:$PORT/auth --data-binary @-)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ] || [ "$http_code" = "000" ]; then
|
||||
echo "FAILED (curl exit=$rc, HTTP=$http_code)"
|
||||
cat "$CURL_OUT"
|
||||
fail $PID "Body within limit was rejected"
|
||||
fi
|
||||
echo "ok (HTTP $http_code)"
|
||||
|
||||
echo -n "Testing body over limit ($((BODY_LIMIT + 1)) bytes)... "
|
||||
http_code=$(head -c $((BODY_LIMIT + 1)) /dev/zero | \
|
||||
curl_post -X POST https://$ADDRESS:$PORT/auth --data-binary @-)
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ] && [ "$http_code" != "413" ] && [ "$http_code" != "431" ]; then
|
||||
echo "FAILED (curl exit=$rc, HTTP=$http_code)"
|
||||
cat "$CURL_OUT"
|
||||
fail $PID "Body over limit was not rejected (HTTP $http_code)"
|
||||
fi
|
||||
echo "ok (HTTP $http_code)"
|
||||
|
||||
# Generate N headers of 1 KB each into $HDRFILE for curl's -H @file.
|
||||
# With a 16 KB limit: 3 headers (3 KB) is within; 20 headers (20 KB) is over.
|
||||
HDR_CHUNK=$((1 * 1024))
|
||||
gen_headers() {
|
||||
n=$1; rm -f "$HDRFILE"; i=0
|
||||
while [ $i -lt $n ]; do
|
||||
{ printf 'X-Test-%d: ' $i
|
||||
head -c ${HDR_CHUNK} /dev/zero | tr '\0' 'A'
|
||||
printf '\n'; } >> "$HDRFILE"
|
||||
i=$((i+1))
|
||||
done
|
||||
}
|
||||
|
||||
echo -n "Testing headers within limit ($((3 * HDR_CHUNK)) bytes)... "
|
||||
gen_headers 3
|
||||
# Explicit Content-Length: 0 is required: older curl (e.g. 7.76.1 on CentOS 9)
|
||||
# omits it for empty bodies, leaving the server unable to determine
|
||||
# message_complete and causing a timeout.
|
||||
http_code=$(curl_post -X POST -H "Content-Length: 0" -H @"$HDRFILE" \
|
||||
https://$ADDRESS:$PORT/auth)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ] || [ "$http_code" = "000" ]; then
|
||||
echo "FAILED (curl exit=$rc, HTTP=$http_code)"
|
||||
cat "$CURL_OUT"
|
||||
fail $PID "Headers within limit were rejected"
|
||||
fi
|
||||
echo "ok (HTTP $http_code)"
|
||||
|
||||
echo -n "Testing headers over limit ($((20 * HDR_CHUNK)) bytes)... "
|
||||
gen_headers 20
|
||||
http_code=$(curl_post -X POST -H "Content-Length: 0" -H @"$HDRFILE" \
|
||||
https://$ADDRESS:$PORT/auth)
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ] && [ "$http_code" != "413" ] && [ "$http_code" != "431" ]; then
|
||||
echo "FAILED (curl exit=$rc, HTTP=$http_code)"
|
||||
cat "$CURL_OUT"
|
||||
fail $PID "Headers over limit were not rejected (HTTP $http_code)"
|
||||
fi
|
||||
echo "ok (HTTP $http_code)"
|
||||
|
||||
rm -f "$HDRFILE" "$CURL_OUT"
|
||||
cleanup
|
||||
exit 0
|
||||
Reference in New Issue
Block a user