Skip to content

HTTP server listens on all interfaces without authentication #1

Description

@lgnap

Context

MainVerticle starts the HTTP server without specifying a listen address:

// web-ui/src/main/java/studio/webui/MainVerticle.java:101
vertx.createHttpServer().requestHandler(router).listen(8080);

Vert.x's listen(int) overload uses the default host, 0.0.0.0: the server is reachable from
every network interface, not just the loopback.

The API mounted at /api has no authentication, and exposes among others:

  • GET /api/library/packs — lists the local library
  • POST /api/library/download — returns a pack's contents
  • POST /api/library/upload — writes a file into the library
  • POST /api/library/convert — triggers a conversion
  • POST /api/library/remove — deletes a pack
  • POST /api/device/addFromLibrary, /removeFromDevice, /dump — drive the connected device

On a shared network — public wifi, a corporate or guest network, a shared flat — any machine on
the same segment can therefore read, write and delete in the user's library while STUdio is
running. Since the application is launched by a script that immediately opens a browser, the
user has no reason to suspect anything is listening beyond the loopback.

The CORS filter at MainVerticle.java:67 (CorsHandler.create("http://localhost:.*")) does not
cover this: CORS is enforced by the browser, on requests issued by a web page. It has no effect
on a direct request from curl, a script, or another application.

Description

Bind the server to the loopback only, which matches what the application is: a desktop tool
whose UI is served at http://localhost:8080 — the very URL MainVerticle opens itself, a few
lines after the listen call.

No functionality is lost: the frontend is served by the same server and loaded from localhost.

A related point, to settle here or in a follow-up: port 8080 is hard-coded. It is very often
already taken, and startup then fails with nothing actionable — listen() with no handler
discards the failure silently. Making address and port configurable (via a system property, as
studio.open already is just below) would address both at once.

Affected files

  • web-ui/src/main/java/studio/webui/MainVerticle.java — the listen call, plus a failure
    handler so that an occupied port is reported
  • web-ui/src/test/java/studio/webui/ — listen test
  • README.md / README_fr.md — document the option if one is added

Implementation plan

  1. Replace listen(8080) with listen(port, host), host defaulting to 127.0.0.1.
  2. Read address and port from system properties (studio.host, studio.port), following the
    convention already established by studio.open.
  3. Pass a handler to listen: log a bind failure explicitly rather than leaving a process
    running that serves nothing.
  4. Build the browser URL from the effective port instead of the http://localhost:8080
    constant.
  5. Test: the running server answers on 127.0.0.1 and does not answer on the machine's
    non-loopback address.

Acceptance criteria

  • By default, the server accepts connections on the loopback only
  • A failed bind (port in use) produces an explicit error in the logs
  • The URL opened in the browser reflects the port actually used
  • Listening on another interface remains possible, but as an explicit choice
  • Automated test covering loopback accepted / external interface refused
  • mvn -Dskip.installnodeyarn=true -Dskip.yarn=true test green on Linux and Windows

Complexity

S — the core fix is one line; most of the work is configurability and the test.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions