Skip to content

Security hardening: enforce connection limit, sanitise errors, harden TLS#304

Open
balat wants to merge 7 commits into
masterfrom
security-hardening
Open

Security hardening: enforce connection limit, sanitise errors, harden TLS#304
balat wants to merge 7 commits into
masterfrom
security-hardening

Conversation

@balat

@balat balat commented Jun 26, 2026

Copy link
Copy Markdown
Member

Security hardening for closer-to-Internet exposure

Following a security audit focused on the question "can ocsigenserver be exposed
directly to the Internet, or does it still need a reverse proxy?". The honest
answer remains: keep a reverse-proxy / TLS-terminating front for now (it
supplies read timeouts, TLS hardening and ACME). But several genuine gaps were
fixed, where existing configuration was silently ignored.

Fixes

  • Connection limit enforced again. <maxconnected> (default 350) was
    tracked but never applied; the accept loop ignored it. It now drives
    conduit's global accept throttle.
  • No exception leak in error responses. handle_error returned
    Printexc.to_string exn as the body for every status except 404, disclosing
    exception constructor names and arguments (file paths, Unix_error, ...).
    Clients now get the generic HTTP status reason phrase (or an extension's
    explicit Ext_http_error message); the detail stays in the logs.
  • TLS hardening. Require TLS 1.2 at minimum (TLS 1.0/1.1 deprecated,
    RFC 8996) and prefer the server's cipher order. The <ciphers>, <dhfile>
    and <curve> entries of <ssl>, until now parsed but never applied, are now
    honoured.
  • Command pipe 0o600. Was 0o660 (group-writable), letting any local
    user in the server's group inject control commands (shutdown, reload, ...).

Documentation

  • TLS section modernised (TLS 1.2 minimum, cipher/dh/curve options, modern key
    advice) and an HTTP→HTTPS redirect recipe (Redirectmod + <ssl/> condition).
  • Honest note that <timeout> is currently not enforced: there is no
    per-connection idle timeout, so the server does not defend against Slowloris
    on its own. A reverse proxy is recommended for Internet-facing deployments.
    Removed the documentation of the non-implemented <keepalivetimeout>.
  • Corrected the <user>/<group> section, which falsely claimed the server
    drops privileges when run as root. They are deprecated and ignored; the doc
    now advises against running as root and lists ways to serve 80/443
    unprivileged (reverse proxy / cap_net_bind_service / port redirection).

Tests

Self-contained cram tests (POSIX sh): command pipe 0o600, generic error body,
and an HTTPS handshake accepting TLS 1.2 / refusing TLS 1.1.

Not addressed (intentionally)

  • Request idle/read timeout (Slowloris). The only hook conduit exposes is a
    total-connection-lifetime cap, which would break comet/long-poll and slow
    large downloads. A real idle timeout needs upstream cohttp support; documented
    as a limitation instead.
  • Privilege dropping, configurable header/line limits, and CL/TE conflict
    validation remain backlog.

balat added 7 commits June 26, 2026 16:18
The <maxconnected> limit was tracked but never applied: the accept loop
ignored it. Drive conduit's global accept throttle with the configured
value so the limit takes effect again.
handle_error returned Printexc.to_string of the exception as the response
body for every status except 404, disclosing exception constructor names
and arguments (file paths, Unix_error details, ...) to clients. Return the
generic status reason phrase instead, or the explicit message an extension
exposes through Ext_http_error. The exception detail stays in the logs.
The control command pipe was group-writable (0o660), letting any local
user in the server's group inject commands (shutdown, reload, clearcache).
Only the server's own user needs to write to it.
Require TLS 1.2 at minimum (TLS 1.0/1.1 deprecated, RFC 8996) and prefer the
server's cipher order on conduit's OpenSSL server context. Also apply the
<ciphers>, <dhfile> and <curve> entries of the <ssl> configuration, which
were parsed but never passed to the TLS context.
- Document the TLS 1.2 minimum and the <ciphers>/<dhfile>/<curve> options,
  and replace the obsolete 1024-bit key advice.
- Add an HTTP->HTTPS redirect recipe using Redirectmod and the <ssl/>
  condition of Accesscontrol.
- State honestly that <timeout> is currently not enforced (no per-connection
  idle timeout), that the server does not defend against Slowloris on its own,
  and recommend a reverse proxy for Internet-facing deployments. Remove the
  documentation of the non-implemented <keepalivetimeout> option.
Self-contained cram tests (POSIX sh, no bash helper) for the security
hardening:
- security.t: the command pipe is created 0o600 (F8); a handler error returns
  a generic body, never the OCaml exception (F4).
- security-tls.t: an HTTPS listener accepts TLS 1.2 and refuses TLS 1.1 (F5).
The manual claimed the server drops privileges when launched as root. It no
longer does: <user>/<group> are deprecated and ignored. Document this, advise
against running as root, and list the supported ways to serve ports 80/443 as
an unprivileged user. Remove the misleading <user>/<group> lines from the
sample configurations.
@balat balat force-pushed the security-hardening branch from e46f173 to bb621ad Compare June 26, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant