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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ curl -H "X-Proxy-Token: mysecrettoken" https://your-tunnel.proxyhub.cloud/
| `-t, --token <token>` | Token for tunnel protection |
| `-i, --inspect` | Enable request inspector UI |
| `--inspect-port <port>` | Port for inspector UI (default: port + 1000) |
| `-k, --auth-key <key>` | Authentication key for the ProxyHub server |
| `-d, --debug` | Enable debug mode |
| `-V, --version` | Output version number |
| `-h, --help` | Display help |
Expand Down Expand Up @@ -182,6 +183,11 @@ PROXYHUB_SOCKET_URL=https://your-server.com proxyhub -p 3000
| `PROTOCOL` | `https` | Protocol for generated URLs |
| `SOCKET_PATH` | `/socket.io` | Socket.IO path |
| `CONNECTION_TIMEOUT_MINUTES` | `30` | Session timeout (0 = unlimited) |
| `SOCKET_AUTH_KEY` | - | Shared key for socket authentication |
| `ALLOWED_ORIGINS` | - | Comma-separated list of allowed CORS origins |
| `RATE_LIMIT_WINDOW_MS` | `600000` | HTTP rate limit window (ms) |
| `RATE_LIMIT_MAX_REQUESTS` | `5000` | Max HTTP requests per window |
| `SOCKET_MAX_CONNECTIONS_PER_MINUTE` | `30` | Max socket connections per IP per minute |

### Client

Expand All @@ -190,6 +196,8 @@ PROXYHUB_SOCKET_URL=https://your-server.com proxyhub -p 3000
| `PROXYHUB_SOCKET_URL` | `https://connect.proxyhub.cloud` | ProxyHub server URL |
| `PROXYHUB_SOCKET_PATH` | `/socket.io` | Socket.IO path |
| `PROXYHUB_TOKEN` | - | Token for tunnel protection |
| `PROXYHUB_AUTH_KEY` | - | Authentication key for the server |
| `PROXYHUB_ALLOW_INSECURE` | - | Allow self-signed TLS certificates |

## How It Works

Expand All @@ -206,6 +214,20 @@ Internet Request Your Local Server
(proxyhub.cloud) (your machine)
```

## Security

ProxyHub includes several security features for production use:

- **Socket authentication** — set `SOCKET_AUTH_KEY` on the server and `--auth-key` on the client to restrict connections
- **TLS verification** — enabled by default; opt out with `PROXYHUB_ALLOW_INSECURE` for self-signed certs
- **Rate limiting** — HTTP (5000 requests/10 min) and WebSocket (30 connections/min per IP) rate limits protect against abuse
- **CORS restrictions** — configure `ALLOWED_ORIGINS` to restrict cross-origin access
- **Security headers** — helmet middleware sets secure HTTP response headers
- **Header filtering** — hop-by-hop headers are stripped from proxied requests
- **Unpredictable tunnel IDs** — cryptographically random tunnel URLs

See [SECURITY.md](SECURITY.md) for full details, configuration options, and the list of fixed security issues.

## Development

```bash
Expand Down
125 changes: 125 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Security

ProxyHub takes security seriously. This document describes the security features available, known issues that have been addressed, and how to configure security options.

## Security Features

### Socket.IO Authentication

Restrict which clients can connect to your ProxyHub server by setting a shared authentication key.

**Server:**

```bash
SOCKET_AUTH_KEY=your-secret-key node dist/index.js
```

**Client:**

```bash
proxyhub -p 3000 --auth-key your-secret-key

# Or via environment variable
PROXYHUB_AUTH_KEY=your-secret-key proxyhub -p 3000
```

When `SOCKET_AUTH_KEY` is set on the server, only clients providing the matching key can establish a tunnel. When unset, any client can connect (backward compatible).

Authentication uses `crypto.timingSafeEqual` to prevent timing attacks.

### TLS Certificate Verification

The client enforces TLS certificate verification by default. To allow self-signed certificates (e.g., in development), set:

```bash
PROXYHUB_ALLOW_INSECURE=1 proxyhub -p 3000
```

### CORS Restrictions

**Server:** Restrict allowed origins for HTTP and WebSocket connections:

```bash
ALLOWED_ORIGINS=https://example.com,https://app.example.com node dist/index.js
```

When unset, all origins are allowed (backward compatible).

**Inspector:** The inspector UI only accepts CORS requests from `localhost` and `127.0.0.1`.

### Token Protection

Secure individual tunnels with per-tunnel tokens:

```bash
proxyhub -p 3000 --token mysecrettoken
```

Requests must include the `X-Proxy-Token` header. See the main [README](README.md#token-protection) for details.

### Rate Limiting

**HTTP requests** are rate-limited by default (5000 requests per 10-minute window per IP). The `/status` and `/health` endpoints are excluded.

**Socket.IO connections** are limited to 30 connections per minute per IP.

Configure via environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `RATE_LIMIT_WINDOW_MS` | `600000` (10 min) | HTTP rate limit window in milliseconds |
| `RATE_LIMIT_MAX_REQUESTS` | `100` | Max HTTP requests per window per IP |
| `SOCKET_MAX_CONNECTIONS_PER_MINUTE` | `10` | Max socket connections per minute per IP |

### Security Headers

The server uses [helmet](https://helmetjs.github.io/) to set secure HTTP headers including Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and others.

### Request Body Limits

The server limits request bodies to 10 MB to prevent denial-of-service via oversized payloads.

### Header Filtering

Hop-by-hop headers (`Transfer-Encoding`, `Connection`, `Keep-Alive`, `Upgrade`, `TE`, `Trailer`, `Proxy-Authenticate`, `Proxy-Authorization`) are stripped from proxied requests to prevent header injection and protocol confusion attacks.

### Unpredictable Tunnel IDs

Tunnel IDs are generated using `crypto.randomBytes(16)` (32-character hex strings) instead of deterministic hashes. IDs are persisted in `~/.proxyhub/tunnel-ids.json` for stability across restarts while remaining unpredictable to attackers.

## Fixed Security Issues

| ID | Severity | Issue | Fix |
|----|----------|-------|-----|
| H8 | High | Vulnerable dependencies | Updated dependencies via `npm audit fix` |
| H4 | High | Hop-by-hop headers forwarded to tunnels | Headers are now stripped before forwarding |
| H3 | High | No request body size limit | Added 10 MB limit on JSON and URL-encoded bodies |
| H1 | High | No rate limiting | Added HTTP and Socket.IO rate limiting |
| C1 | Critical | No socket authentication | Added opt-in shared-key authentication with timing-safe comparison |
| C2 | Critical | TLS certificate verification disabled | Enabled by default; opt-out via `PROXYHUB_ALLOW_INSECURE` |
| C3 | Critical | Predictable tunnel IDs | Replaced MD5-based IDs with cryptographically random IDs |
| C4 | Critical | Unrestricted CORS | Server respects `ALLOWED_ORIGINS`; inspector restricted to localhost |
| M3 | Medium | Missing security headers | Added helmet middleware |

## Environment Variables Reference

### Server

| Variable | Default | Description |
|----------|---------|-------------|
| `SOCKET_AUTH_KEY` | unset (no auth) | Shared key for socket authentication |
| `ALLOWED_ORIGINS` | unset (allow all) | Comma-separated list of allowed CORS origins |
| `RATE_LIMIT_WINDOW_MS` | `600000` | HTTP rate limit window (ms) |
| `RATE_LIMIT_MAX_REQUESTS` | `5000` | Max HTTP requests per window |
| `SOCKET_MAX_CONNECTIONS_PER_MINUTE` | `30` | Max socket connections per IP per minute |

### Client

| Variable | Default | Description |
|----------|---------|-------------|
| `PROXYHUB_AUTH_KEY` | unset (random) | Authentication key sent to the server |
| `PROXYHUB_ALLOW_INSECURE` | unset (TLS on) | Set to allow self-signed TLS certificates |

## Reporting Vulnerabilities

If you discover a security vulnerability, please report it responsibly by opening a private issue on [GitHub](https://github.com/cube-root/proxyhub/issues) or contacting the maintainers directly. Do not disclose vulnerabilities publicly until a fix is available.
Loading