Skip to content

Security: Dyalog/Jarvis

Security

docs/security.md

This page covers the security-related features of Jarvis: encrypting the connection with TLS, authenticating requests, and validating them before your endpoint code runs.

Using TLS

By default Jarvis serves plain HTTP. To serve HTTPS (TLS), set Secure to 1 and tell Jarvis where to find the server's certificate and private key:

  • Certificate and key files: set ServerCertFile to the public certificate file and ServerKeyFile to the private key file.
  • Windows certificate store: alternatively, on Windows, set ServerCertSKI to the certificate's Subject Key Identifier and Jarvis will load it from the Microsoft Certificate Store.
  • Root certificates: RootCertDir names a folder of root CA certificates. On Windows, leaving it empty uses the operating system's certificate store.
j←Jarvis.New ''
j.Secure←1
j.ServerCertFile←'/path/to/server-cert.pem'
j.ServerKeyFile←'/path/to/server-key.pem'
j.Start

SSLValidation controls how Jarvis treats client certificates. The default, 64, requests a client certificate but does not require one; when a client presents one, it is available to your code as req.PeerCert. See Priority for the cipher/protocol settings passed to Conga.

TLS underpins the other features here: HTTP Basic credentials and session tokens are only as safe as the connection carrying them, so run a service that authenticates its users over HTTPS.

Authentication

Authentication decides who may call your service. Jarvis runs an authentication hook for each request, before your endpoint code: set AuthenticateFn to the name of a function in CodeLocation. The function is passed the Request instance and returns:

  • 0 — the request is authenticated, or no authentication is required, so processing continues;
  • non-0 — authentication failed; Jarvis fails the request with HTTP status 401 (Unauthorized).

If the function signals an error, Jarvis fails the request with 500.

Your function can base its decision on whatever the request carries — the UserID and Password from HTTP Basic authentication (below), a bearer token or API key in a header, a cookie, or session state.

∇ r←Authenticate req
⍝ AuthenticateFn: allow a request only if it carries a known API key
  r←~(⊂req.GetHeader'x-api-key')∊KnownKeys
∇

If no AuthenticateFn is defined, every request is allowed (subject to validation and, for WebSockets, WsAuthenticateFn). WebSocket connections authenticate separately; see Using WebSockets.

HTTP Basic Authentication

HTTP Basic authentication is the scheme in which the client sends a user name and password in the Authorization header. It is controlled by HTTPAuthentication, which defaults to 'basic'; set it to '' to disable Basic authentication.

Jarvis handles two parts of the scheme for you:

  • Decoding credentials. When a request carries an Authorization: Basic … header, Jarvis decodes it and sets req.UserID and req.Password, ready for your AuthenticateFn to check.
  • Challenging the client. When HTTPAuthentication is 'basic' and your AuthenticateFn rejects a request (returns non-0), Jarvis adds a WWW-Authenticate: Basic header to the 401 response, which prompts a browser to ask the user for credentials.

Jarvis does not decide whether the credentials are valid — that is your AuthenticateFn's job:

∇ r←Authenticate req
⍝ AuthenticateFn: check the Basic-auth user name and password
  r←~(req.UserID req.Password)≡'admin' 'secret'
∇

Basic authentication sends the user name and password only Base64-encoded, not encrypted, so always use it over TLS.

Validation

Validation decides whether a request is acceptable — its shape, headers, size, content-type and so on — independently of who sent it. Set ValidateRequestFn to the name of a function in CodeLocation. It is called for every request, is passed the Request instance, and returns:

  • 0 — the request is acceptable, so processing continues;
  • non-0 — the request is rejected; Jarvis fails it with HTTP status 400 (Bad Request).

ValidateRequestFn runs before AuthenticateFn, so use it for checks that don't depend on identity — for example rejecting an unexpected content-type or an over-large body:

∇ r←Validate req
⍝ ValidateRequestFn: require JSON requests no larger than 1 MB
  r←(~'application/json'≡req.ContentType)∨(1e6<≢req.Body)
∇

The hook can also adjust the request's response before failing it — for example to set a custom status or an explanatory payload.

There aren't any published security advisories