Liking cljdoc? Tell your friends :D

dev.arkaitz.web-base.security

Web security measures that are neither authentication nor authorisation (SPEC §15): response headers added when absent, the host's Content Security Policy with a per-request nonce, opt-in trust of a reverse proxy's headers, and CSRF protection through ring-anti-forgery's synchroniser token.

Written down so it is not rediscovered: htmx's hx-on, hx-vals js: and trigger filters need unsafe-eval or the hx-csp extension; a strict policy means doing without them, which the demo does.

Web security measures that are neither authentication nor authorisation
(SPEC §15): response headers added when absent, the host's Content Security
Policy with a per-request nonce, opt-in trust of a reverse proxy's headers,
and CSRF protection through ring-anti-forgery's synchroniser token.

Written down so it is not rediscovered: htmx's `hx-on`, `hx-vals js:` and
trigger filters need `unsafe-eval` or the `hx-csp` extension; a strict
policy means doing without them, which the demo does.
raw docstring

body-failureclj

(body-failure e)

The request body's own failure somewhere in e's cause chain, as data — {:status 413} past its limit, {:status s :lost class-name} when the client did not send it — or nil. Marked where the body is read, so a failure of anything else that merely looks like Jetty's (an upstream client, a driver) is never mistaken for the client's.

The request body's own failure somewhere in `e`'s cause chain, as data — `{:status
413}` past its limit, `{:status s :lost class-name}` when the client did not send it —
or nil. Marked where the body is read, so a failure of anything else that merely looks
like Jetty's (an upstream client, a driver) is never mistaken for the client's.
sourceraw docstring

csrf-fieldclj

(csrf-field request)

The hidden input a classic form needs; htmx requests carry the header instead. Nothing when the request carries no token — under :csrf false there is nothing to send, and an empty field would only earn a 403.

The hidden input a classic form needs; htmx requests carry the header
instead. Nothing when the request carries no token — under `:csrf false`
there is nothing to send, and an empty field would only earn a 403.
sourceraw docstring

csrf-headerclj

source

csrf-tokenclj

(csrf-token request)

The request's token, for the host's own markup — and the read that makes it stick: a token nobody read through here is not written into the session (wrap-csrf).

The request's token, for the host's own markup — and the read that makes it stick:
a token nobody read through here is not written into the session (`wrap-csrf`).
sourceraw docstring

default-headersclj

source

default-max-body-bytesclj

The largest request body the base reads when the host names no other: 200 000 bytes, Jetty's own form limit — which never applied here, because Ring reads the body itself (wrap-params), so a single anonymous POST could fill the heap (measured: 1 GB raised it by 2 GB; four at once, an OutOfMemoryError).

The largest request body the base reads when the host names no other: 200 000 bytes,
Jetty's own form limit — which never applied here, because Ring reads the body itself
(`wrap-params`), so a single anonymous POST could fill the heap (measured: 1 GB raised
it by 2 GB; four at once, an OutOfMemoryError).
sourceraw docstring

privateclj

(private response)

response with Cache-Control: no-store unless it already says how it may be cached. For what is somebody's own — a signed-in page, a page carrying a session's CSRF token — which a shared cache must never hand to the next visitor, nor a shared computer keep.

`response` with `Cache-Control: no-store` unless it already says how it may be cached.
For what is somebody's own — a signed-in page, a page carrying a session's CSRF token —
which a shared cache must never hand to the next visitor, nor a shared computer keep.
sourceraw docstring

rotate-tokenclj

(rotate-token request)

request carrying a fresh CSRF token for a response that rotates the session, and the token recorded so the rotated session keeps exactly it. The render step calls it before turning such a response into HTML, so a login page's forms carry the token its new session holds. The request unchanged when it went through no CSRF, or carries no token. A token read before this — a handler whose own content called csrf-field — cannot follow the rotation, and is logged by name.

`request` carrying a fresh CSRF token for a response that rotates the session, and
the token recorded so the rotated session keeps exactly it. The render step calls it
before turning such a response into HTML, so a login page's forms carry the token its
new session holds. The request unchanged when it went through no CSRF, or carries no
token. A token read before this — a handler whose own content called `csrf-field` —
cannot follow the rotation, and is logged by name.
sourceraw docstring

wrap-body-limitclj

(wrap-body-limit handler limit-for render)

Refuses a request body larger than (limit-for request) bytes with a 413: at once, unread, when its declared length says so; otherwise as it is read, whoever reads it. render answers the refusal made here, before anything else runs.

Refuses a request body larger than `(limit-for request)` bytes with a 413: at once,
unread, when its declared length says so; otherwise as it is read, whoever reads it.
`render` answers the refusal made here, before anything else runs.
sourceraw docstring

wrap-csrfclj

(wrap-csrf handler render-error)

ring-anti-forgery inside the session: every request not GET/HEAD/OPTIONS needs the session's token, read from the __anti-forgery-token form field or the X-CSRF-Token header — which the shell makes htmx send on every request (the library also honours X-XSRF-Token; the base documents one name). A refusal is the base's own 403 datum, so an htmx swap receives a fragment and a navigation a page.

A token reaches the session only if the request used it — through csrf-token or csrf-field, which the shell calls for every page it renders, and while the handler runs. A request that renders neither writes no session, so an anonymous /health, a JSON answer or a redirect leaves no row behind. Reading :anti-forgery-token or ring-anti-forgery's dynamic var directly, or reading the token after the handler returned (a body built lazily later), mints a token that is never stored: the form built with it earns a 403.

ring-anti-forgery inside the session: every request not GET/HEAD/OPTIONS
needs the session's token, read from the `__anti-forgery-token` form field
or the `X-CSRF-Token` header — which the shell makes htmx send on every
request (the library also honours `X-XSRF-Token`; the base documents one
name). A refusal is the base's own 403 datum, so an htmx swap receives a
fragment and a navigation a page.

**A token reaches the session only if the request used it** — through
`csrf-token` or `csrf-field`, which the shell calls for every page it renders,
and while the handler runs. A request that renders neither writes no session, so
an anonymous `/health`, a JSON answer or a redirect leaves no row behind. Reading
`:anti-forgery-token` or ring-anti-forgery's dynamic var directly, or reading the
token after the handler returned (a body built lazily later), mints a token that is
never stored: the form built with it earns a 403.
sourceraw docstring

wrap-headersclj

(wrap-headers handler {:keys [csp] :as config})

Outer middleware: every response — routed, static, error — gets the security headers it lacks; a header the handler set is kept. Every request gets :wb/nonce; when the host configures :csp, {nonce} in it is replaced by that request's nonce and the policy is sent. :frame-options is DENY by default, a string to change it, false to omit it.

Outer middleware: every response — routed, static, error — gets the
security headers it lacks; a header the handler set is kept. Every request
gets `:wb/nonce`; when the host configures `:csp`, `{nonce}` in it is
replaced by that request's nonce and the policy is sent. `:frame-options`
is `DENY` by default, a string to change it, `false` to omit it.
sourceraw docstring

wrap-proxyclj

(wrap-proxy handler hops)

Trusts X-Forwarded-For and X-Forwarded-Proto for :remote-addr and :scheme, behind hops proxies the host runs, each APPENDING what it saw — nginx's $proxy_add_x_forwarded_for, AWS's load balancers, Heroku's and Fly's routers all do. The entry hops from the right is the address the outermost of them saw; everything to its left the client could have written. A header with fewer entries than hops leaves the socket's address, and a request that did not come through the proxies is never trusted beyond it. X-Forwarded-Proto is taken from its last entry whatever the count: proxies overwrite it rather than append, so it holds one value, the nearest proxy's. Only behind proxies the host controls: anyone else can send these headers.

Trusts `X-Forwarded-For` and `X-Forwarded-Proto` for `:remote-addr` and `:scheme`,
behind `hops` proxies the host runs, each APPENDING what it saw — nginx's
`$proxy_add_x_forwarded_for`, AWS's load balancers, Heroku's and Fly's routers all do.
The entry `hops` from the right is the address the outermost of them saw; everything
to its left the client could have written. A header with fewer entries than `hops`
leaves the socket's address, and a request that did not come through the proxies is
never trusted beyond it. `X-Forwarded-Proto` is taken from its last entry whatever the
count: proxies overwrite it rather than append, so it holds one value, the nearest
proxy's. Only behind proxies the host controls: anyone else can send these headers.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close