Security: Add HMAC validation for short URLs + improve privacy documentation

- Implement HMAC-SHA256 signatures on short URLs to detect server-side tampering
- Add client-side signature verification with hostname-derived secret
- New API endpoint: /api/check-short.php for integrity verification
- Update verify.php with privacy notice (addresses not stored)
- Update README to clarify minimal backend requirement (short URLs, rate caching, proof storage)
- Add toast warning when signature mismatch detected
- Support both old and new format in s.php for backward compatibility
- Update all i18n translations (EN, DE, FR, IT, ES, PT, RU)

Addresses security concern: Server compromise could previously result in address
substitution for short-linked invoices. Now client-side verification detects tampering.
This commit is contained in:
Alexander Schmidt
2026-03-26 06:52:20 +01:00
parent c1bd97948c
commit 7e325abf7d
7 changed files with 167 additions and 19 deletions

50
api/check-short.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
/**
* Short URL Integrity Verification API
* GET: Return the hash and HMAC signature for client-side verification
*
* Security: Allows client-side verification that the hash has not been
* tampered with by the server. The signature is verified using the
* hostname as part of the secret HMAC key.
*/
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit;
}
$code = $_GET['code'] ?? '';
if (empty($code) || !preg_match('/^[a-z0-9]{4,10}$/', $code)) {
http_response_code(400);
echo json_encode(['error' => 'Invalid code']);
exit;
}
$dbFile = __DIR__ . '/../data/urls.json';
if (!file_exists($dbFile)) {
http_response_code(404);
echo json_encode(['error' => 'Invoice not found']);
exit;
}
$urls = json_decode(file_get_contents($dbFile), true) ?: [];
if (!isset($urls[$code])) {
http_response_code(404);
echo json_encode(['error' => 'Invoice not found']);
exit;
}
$data = $urls[$code];
$hash = is_array($data) ? $data['h'] : $data;
$signature = is_array($data) ? $data['s'] : null;
// Return hash and signature for client-side verification
echo json_encode([
'code' => $code,
'hash' => $hash,
'signature' => $signature
]);