Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,56 @@ escalate to the OpenJS Foundation CNA at `security@lists.openjsf.org`.

If the project acknowledges your report but does not provide any further
response or engagement within 14 days, escalation is also appropriate.

## Threat Model

The Perspective WebSocket `Server` (the Python `tornado.py`/`aiohttp.py`/
`starlette.py` adapters and the Node `WebSocketServer`) is not a security
boundary against its `Client`. Any `Client` that can send messages to a
`Server` is treated as the author of the queries it submits, and is permitted
to create or delete `Table`/`View` resources, author arbitrary
[expression columns](./docs/md/explanation/view/config/expressions.md), and —
for `Virtual Server` backends (DuckDB, ClickHouse, Polars, custom
`VirtualServerHandler`) — author SQL fragments executed under the configured
database role. The `Virtual Server` SQL builder does not parameterize or
validate client-supplied identifiers, expressions, or operators, because
there is no privilege boundary inside the engine for it to enforce.

The bundled WebSocket adapters above are reference integrations: they do not
implement authentication, authorization, CSRF protection, rate limiting, or
origin enforcement, and are not intended to be exposed directly to untrusted
networks. Production deployments must place an authenticating reverse proxy,
application-framework middleware, or API gateway between the network and the
`Server`.

### In-browser WASM deployments are not affected

This applies only when the `Server` runs in a separate process reached
over a network transport (WebSocket). In-browser deployments — including
`perspective` running entirely in a Web Worker, the
[`perspective-server` WASM build](./docs/md/explanation/architecture.md),
[`duckdb-wasm`](./docs/md/how_to/javascript/virtual_server/duckdb.md),
and any other `Virtual Server` whose backend executes inside the browser
tab — do not have this concern. The `Client` and `Server` share a single
security context (the browser tab, under the same-origin policy of the
embedding page), there is no network transport for a third-party principal
to reach, and the only principal who can submit queries is the same user who
loaded the page. SQL or expression "injection" by that user against a backend
running inside their own tab is not a privilege escalation.

### In scope

The following remain in scope for security reports:

- Memory-safety bugs in the C++ engine, Rust crates, or WASM module.
- Bugs in the `<perspective-viewer>` Shadow DOM, CSS, or sanitization paths
that allow injected markup or styles to escape the component or affect
the embedding page.
- Crashes, hangs, panics, or denial-of-service in the engine reachable from
well-formed protobuf messages.
- Breaches of the trust model above — for example, a `Client` causing effects
on a different `Client`'s `Server` state in a configuration where those
`Client`s share a `Server` but are intended to be isolated, or an
expression column reaching state outside the `Server` it was authored
against.
- Vulnerabilities in the published artifacts themselves (supply-chain).
32 changes: 32 additions & 0 deletions docs/md/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,38 @@ of each mode.
<!-- _Related:
[#2916](https://github.com/perspective-dev/perspective/discussions/2916)_ -->

### Is the WebSocket Perspective `Server` safe to expose to untrusted clients?

No. The WebSocket `Server` is not a security boundary. Every connected `Client`
is treated as the author of the queries it submits, and is permitted to create
and delete `Table`/`View` resources, author arbitrary
[expression columns](./explanation/view/config/expressions.md), and — for
[Virtual Server](./explanation/virtual_servers.md) backends like DuckDB or
ClickHouse — author SQL fragments executed under the configured database
role. The bundled WebSocket adapters
(`tornado.py`/`aiohttp.py`/`starlette.py`/`WebSocketServer`) are reference
integrations and do not authenticate, authorize, or enforce origin policy.

WebSocket Deployments that need per-user isolation must put an authenticating
proxy in front of the `Server`, run a least-privileged database role for any
`Virtual Server` backend, and/or isolate users into separate `Server`
instances. See [`SECURITY.md`](../../SECURITY.md) for the full threat model
and deployment guidance.

Obviously, none of this applies to WASM DBs like Perspective and DuckDB.

### Does Perspective sanitize SQL `Virtual Server`s?

No, by design. [Virtual Server](./explanation/virtual_servers.md) backends
interpolate client-supplied `view_id`, `table_id`, `column_name`, expression
strings, and filter operators directly into SQL templates without
parameterization or whitelist validation. The `Client` is the author of the
queries — there is no privilege boundary inside the engine for sanitization
to enforce. If your deployment needs to restrict the SQL surface area exposed
to a `Client`, the supported boundary is the database role the `Virtual Server`
is configured with (read-only etc), or better complete isolation via WASM
backend.

### How do I set up WebSocket authentication?

The [`WebSocketServer`](./how_to/javascript/nodejs_server.md) does not include
Expand Down
12 changes: 12 additions & 0 deletions rust/perspective-js/src/ts/perspective.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ function buffer_to_arraybuffer(
}
}

/**
* A simple Node `http`-based WebSocket adapter that exposes a
* `PerspectiveServer` over the wire.
*
* @remarks
*
* **Security.** `WebSocketServer` is a reference integration with no
* authentication, authorization, origin enforcement, or rate limiting, and
* is not safe to expose to untrusted networks — see
* [`SECURITY.md`](https://github.com/perspective-dev/perspective/blob/master/SECURITY.md)
* for the full threat model.
*/
export class WebSocketServer {
_server: http.Server | any; // stoppable has no type ...
_wss: HttpWebSocketServer;
Expand Down
8 changes: 8 additions & 0 deletions rust/perspective-python/perspective/handlers/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ class PerspectiveAIOHTTPHandler(object):
The Perspective client and server will automatically keep the Websocket
alive without timing out.

# Security

`PerspectiveAIOHTTPHandler` is a reference integration with no
authentication, authorization, origin enforcement, or rate limiting,
and is not safe to expose to untrusted networks — see
[`SECURITY.md`](https://github.com/perspective-dev/perspective/blob/master/SECURITY.md)
for the full threat model.

# Examples

>>> server = Server()
Expand Down
8 changes: 8 additions & 0 deletions rust/perspective-python/perspective/handlers/starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
class PerspectiveStarletteHandler(object):
"""`PerspectiveStarletteHandler` is a drop-in implementation of Perspective.

# Security

`PerspectiveStarletteHandler` is a reference integration with no
authentication, authorization, origin enforcement, or rate limiting,
and is not safe to expose to untrusted networks — see
[`SECURITY.md`](https://github.com/perspective-dev/perspective/blob/master/SECURITY.md)
for the full threat model.

# Examples

>>> server = Server()
Expand Down
8 changes: 8 additions & 0 deletions rust/perspective-python/perspective/handlers/tornado.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ class PerspectiveTornadoHandler(WebSocketHandler):
to the `tornado.web.Application` constructor, as well as provide the
`max_buffer_size` optional arg, for large datasets.

# Security

`PerspectiveTornadoHandler` is a reference integration with no
authentication, authorization, origin enforcement, or rate limiting,
and is not safe to expose to untrusted networks — see
[`SECURITY.md`](https://github.com/perspective-dev/perspective/blob/master/SECURITY.md)
for the full threat model.

# Arguments

- `loop`: An optional `IOLoop` instance to use for scheduling IO calls,
Expand Down
Loading