This guide documents frontend security hardening updates to secure on-premise AgileSec deployments.
Overview
This guide documents four hardening updates to the HAProxy edge configuration for on-premise AgileSec platforms. Each hardening control is enforced uniformly across all backend services from a single point as every client response passes through HAProxy. Together, these hardening updates reduce AgileSec’s browser-facing attack surface, eliminate server fingerprinting, and remove legacy TLS exposure.
|
Configuration |
Remediation |
|
|---|---|---|
|
1 |
HTTP Security Headers |
Configure HTTP Security Headers to protect from browser-based vulnerabilities with |
|
2 |
Content Security Policy (CSP) |
Configure CSP header to restrict which sources the browser is permitted to load resources from, protecting against cross-site scripting (XSS) and data injection attacks. |
|
3 |
Server Technology Disclosure |
Configure removal of server technology disclosing headers at the HAProxy layer to ensure they are stripped before reaching any client. |
|
4 |
TLS 1.3 Configuration Update |
Configure HAProxy SSL configuration to enforce TLS 1.3 exclusively and remove the TLS 1.2 attack surface entirely. |
Note about CORS Policy Configuration: In 3.5.0 and higher, the application's Cross-Origin Resource Sharing (CORS) is configurable through the environment variable CORS_WHITE_LIST set in <agilesec_install_dir>/config_envs/api on frontend nodes. By default, it is set to allow AgileSec external FQDN and updating it is not needed to enforce CORS policy.
Deployment port 8443 note: This guide uses both the standard HTTPS listener, bind :443 ssl ..., and examples without an explicit port. If HTTPS is exposed directly on port 8443, configure the client-facing HAProxy frontend with bind :8443 ssl ... and add :8443 to all validation URLs. For example:https://<agilesec-fqdn>:8443/health-check.
Note: If using non-privileged port 8443, do not use sudo with ./manage.sh.
Prerequisites
Ensure the following prerequisites are met.
Set Environment Variables
Set environment variables to easily copy and paste instructions.
-
$agilesec_install_dir: the location where AgileSec will be installed to.
export agilesec_install_dir=</path/to/installation>
Backup Frontend HAProxy Configuration
Important: Make a backup of your frontend node HAProxy configuration before proceeding with any changes!
cp $agilesec_install_dir/services/haproxy/haproxy.cfg $agilesec_install_dir/services/haproxy/haproxy.cfg.bak
HTTP Security Headers Configuration
Configure HTTP Security Headers to protect from browser-based vulnerabilities with X-Frame-Options, X-Content-Type Options, and Strict-Transport-Security.
Add the following directives to the https_frontend_local section in $agilesec_install_dir/services/haproxy/haproxy.cfg on frontend nodes:
frontend https_frontend_local
bind :443 ssl ...
...
# Security headers
http-request set-var(txn.file_path) path
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Force correct MIME type and download behavior for file download endpoints
http-response set-header Content-Type "application/zip" if { var(txn.file_path) -m sub /v1/file-upload/local/ }
http-response set-header Content-Disposition "attachment" if { var(txn.file_path) -m sub /v1/file-upload/local/ }
http-response set-header Content-Type "application/octet-stream" if { var(txn.file_path) -m sub /v1/platform-sensors/remote-sensor/ }
Note: These directives must be placed inside a frontend or listen section. HAProxy does not allow http-response rules in the defaults section. http-request directive must be added before the http-response directives
Validate and reload HAProxy:
cd $agilesec_install_dir/services/haproxy
./haproxy -c -f haproxy.cfg
cd $agilesec_install_dir/scripts
sudo ./manage.sh restart haproxy
Note: HAProxy config validation must show no alerts.
Note: If using non-privileged port 8443, do not use sudo with ./manage.sh.
Verify headers are present in the response:
curl -I https://<agilesec-fqdn>/health-check
Expected response headers:
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
strict-transport-security: max-age=31536000; includeSubDomains; preload
Result: X-Frame-Options, X-Content-Type-Options, and Strict-Transport-Security should appear in the response headers.
Content Security Policy (CSP) Configuration
A CSP header restricts which sources the browser is permitted to load resources from, protecting against cross-site scripting (XSS) and data injection attacks.
On frontend nodes, add the following http-response directives to the https_frontend_local section in $agilesec_install_dir/services/haproxy/haproxy.cfg, after the existing security headers:
frontend https_frontend_local
...
# Content Security Policy
http-response set-header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' wss://<agilesec-fqdn>;"
Note: Replace <agilesec-fqdn> with your actual external FQDN for WebSocket connections (e.g. wss://agilesec.kf-agilesec.com). The unsafe-inline and unsafe-eval directives are required to support the platform frontend framework.
Note: If using non-privileged port 8443, please use wss://agilesec.kf-agilesec.com:8443 for WebSocket connections.
Validate and reload HAProxy:
cd $agilesec_install_dir/services/haproxy
./haproxy -c -f haproxy.cfg
cd $agilesec_install_dir/scripts
sudo ./manage.sh restart haproxy
Note: HA proxy config validation must show no alerts.
Note: If using non-privileged port 8443, do not use sudo with ./manage.sh.
After reloading HAProxy, verify the CSP header is returned by inspecting the response from the sign-in page:
curl -I https://<agilesec-fqdn>/signin
Expected response header:
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline'
'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
connect-src 'self' wss://<agilesec-fqdn>;
Result: The content-security-policy header should appear in the response confirming the directive is applied at the HAProxy layer.
Server Technology Disclosure Configuration
By default, backend applications include HTTP response headers identifying server technology in use. Two headers are of particular concern:
-
x-powered-by: Expressorx-powered-by: Next.js– directly identifies the application framework -
server:– identifies the underlying web server software and version
Removing these headers at the HAProxy layer ensures they are stripped before reaching any client.
Locate the frontend section in your $agilesec_install_dir/services/haproxy/haproxy.cfg on frontend nodes handling client-facing traffic. Add the following two lines inside the frontend section section to strip server fingerprinting headers:
frontend https_frontend_local
bind *:443 ssl ...
...
# Strip server fingerprinting headers
http-response del-header x-powered-by
http-response del-header server
default_backend ...
Note: These directives must be placed inside a frontend or listen section, not in the defaults section.
Validate and reload HAProxy:
cd $agilesec_install_dir/services/haproxy
./haproxy -c -f haproxy.cfg
cd $agilesec_install_dir/scripts
sudo ./manage.sh restart haproxy
Verify the headers are removed by inspecting the response from health-check and signin URLs:
curl -I https://<agilesec-fqdn>/health-check
curl -I https://<agilesec-fqdn>/signin
Result: The x-powered-by and server headers should no longer appear in the responses. All other headers remain unaffected.
TLS 1.3 Configuration Update
Current HAProxy SSL configuration already disables SSLv3, TLS 1.0, and TLS 1.1. However, TLS 1.2 is still permitted for broader compatibility. To enforce TLS 1.3 exclusively and remove the TLS 1.2 attack surface entirely, make the following configuration updates to $agilesec_install_dir/services/haproxy/haproxy.cfgon frontend nodes:
-
Add
no-tlsv12to both thessl-default-bind-optionsandssl-default-server-optionslines. -
Remove the
ssl-default-bind-ciphersandssl-default-server-cipherslines – these are TLS 1.2 cipher lists and have no effect once TLS 1.2 is disabled.
global
...
# TLS 1.3 only – no-tlsv12 added, TLS 1.2 cipher lists removed
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets
ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
Note: Update ciphersuites as needed by your security policies.
Validate and reload HAProxy:
cd $agilesec_install_dir/services/haproxy
./haproxy -c -f haproxy.cfg
cd $agilesec_install_dir/scripts
sudo ./manage.sh restart haproxy
Note: HA proxy config validation must show no alerts.
Note: If using non-privileged port 8443, do not use sudo with ./manage.sh.
Verify TLS 1.3 is enforced and TLS 1.2 is rejected:
# Should succeed
openssl s_client -connect <agilesec-fqdn>:443 -tls1_3
# Should fail with handshake error
openssl s_client -connect <agilesec-fqdn>:443 -tls1_2
Result: The TLS 1.3 connection should complete successfully. The TLS 1.2 attempt should return an alert handshake failure, confirming the restriction is in place.
Note: If using non-privileged port 8443, add SNI to verification to avoid false failures in SNI/certificate-based deployments.