feat: optional API key auth via X-API-Key header or ?key= param

This commit is contained in:
2026-04-21 12:11:23 +02:00
parent e7924f462e
commit efc9e6510c
2 changed files with 26 additions and 0 deletions

View File

@@ -46,6 +46,24 @@ php -S localhost:8080 -t web/
| `docker/start.sh` | Boots PHP-FPM, ChromeDriver, writes config | | `docker/start.sh` | Boots PHP-FPM, ChromeDriver, writes config |
| `docker-compose.yml` | Production compose | | `docker-compose.yml` | Production compose |
## API Key
Set `API_KEY` env var in docker-compose to require authentication on all `/api` requests.
Leave unset (default) for open access.
```bash
# via header (preferred — not logged in access logs)
curl -H "X-API-Key: your-secret-key" "http://host/api?url=https://example.com"
# via query param
curl "http://host/api?key=your-secret-key&url=https://example.com"
```
## SSRF Protection
Set `BLOCK_PRIVATE_IPS=true` to reject requests to LAN, loopback, and cloud metadata IPs.
Recommended when hosting publicly. Default is off (allows local/LAN addresses).
## Caveats ## Caveats
- `web/index.php` has a `var_dump($cmd)` debug statement left in `http2pic.class.php:181` - remove before shipping. - `web/index.php` has a `var_dump($cmd)` debug statement left in `http2pic.class.php:181` - remove before shipping.

View File

@@ -24,6 +24,14 @@ if (php_sapi_name() == 'cli-server' && file_exists(ROOT . DS . 'web' . DS . impl
switch ($url[0]) { switch ($url[0]) {
case 'api': case 'api':
if (defined('API_KEY') && API_KEY !== '') {
$provided = $_SERVER['HTTP_X_API_KEY'] ?? $_REQUEST['key'] ?? '';
if ($provided !== API_KEY) {
header('HTTP/1.0 401 Unauthorized');
echo 'Invalid or missing API key';
exit;
}
}
$target = substr($_SERVER['REQUEST_URI'], 5); $target = substr($_SERVER['REQUEST_URI'], 5);
if (!$target || !filter_var($target, FILTER_VALIDATE_URL)) if (!$target || !filter_var($target, FILTER_VALIDATE_URL))
$target = $_REQUEST['url']; $target = $_REQUEST['url'];