
本文介绍通过时效性访问令牌(token)机制保护音频资源 url,防止未授权直接下载,同时兼容前端流式播放与断点续传需求。
本文介绍通过时效性访问令牌(token)机制保护音频资源 url,防止未授权直接下载,同时兼容前端流式播放与断点续传需求。
在音乐类 Web 应用中,直接暴露如 https://example.com/music/get/5 这类静态 ID 路径存在严重安全隐患:用户可轻易复用链接、分享、爬取甚至批量下载原始音频文件。仅靠前端隐藏或 Referer 校验无法真正防御——HTTP 请求可被任意构造。真正的解决方案是将资源访问权与动态、有时效、带签名的访问凭证绑定,即“安全直链”(Secure Direct Link)。
✅ 推荐方案:带签名与过期时间的 Token 验证
修改路由为带 token 的形式,例如:
/music/get/5?token=abc123&expires=1717029600&signature=8f3a7e...
后端在 get/{id} 处理逻辑中,需完成以下校验:
- 验证 token 有效性与时效性(防止重放攻击);
- 校验 signature 签名(确保参数未被篡改);
- 确认用户权限(如登录态、订阅状态、播放次数限制等);
-
动态生成响应头,支持流式播放(
Accept-Ranges,Content-Range)和跨域播放。
以下是安全化后的 PHP 示例(基于原代码重构):
立即学习“PHP免费学习笔记(深入)”;
<?php
// 假设已引入 $file(MusicModel 实例),且 $secretKey = 'your_app_secret_2024';
$musicId = (int)$_GET['id'] ?? 0;
$token = $_GET['token'] ?? '';
$expires = (int)$_GET['expires'] ?? 0;
$signature = $_GET['signature'] ?? '';
// 1. 基础校验
if (!$musicId || !$token || !$expires || !$signature || time() > $expires) {
http_response_code(403);
exit('Forbidden: Invalid or expired token.');
}
// 2. 签名验证(HMAC-SHA256,防篡改)
$expectedSignature = hash_hmac('sha256', "id={$musicId}&expires={$expires}", $secretKey);
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(403);
exit('Forbidden: Signature mismatch.');
}
// 3. 查询并校验文件权限(示例:仅付费用户可播放)
$user = getCurrentUser(); // 你的认证逻辑(如 JWT 解析或 session)
if (!$user || !$user->hasActiveSubscription()) {
http_response_code(403);
exit('Forbidden: Subscription required.');
}
// 4. 安全输出音频(保留 Range 支持,适配 <audio> 标签)
$filename = $file->link;
$length = $file->size;
// 支持 HTTP Range 请求(关键!否则 Safari/Chrome 拖动失败)
if (isset($_SERVER['HTTP_RANGE'])) {
list($unit, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (trim($unit) !== 'bytes') {
http_response_code(416);
exit('Requested range not satisfiable.');
}
[$start, $end] = explode('-', $range) + [0, $length - 1];
$start = (int)$start;
$end = ($end === '') ? $length - 1 : (int)$end;
if ($start < 0 || $end > $length - 1 || $start > $end) {
http_response_code(416);
exit('Invalid range request.');
}
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes {$start}-{$end}/{$length}");
header("Content-Length: " . ($end - $start + 1));
fseek($fp = fopen($filename, 'rb'), $start);
fpassthru($fp);
fclose($fp);
exit;
}
// 全量响应(fallback)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Expose-Headers: Content-Range, Accept-Ranges');
header('Content-Type: audio/mpeg');
header('Content-Length: ' . $length);
header('Accept-Ranges: bytes');
header('Content-Disposition: inline; filename="' . basename($filename) . '"');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Transfer-Encoding: binary');
readfile($filename);
?>⚠️ 关键注意事项
- 永远不要将原始文件路径直接暴露给前端:前端只应持有带签名的临时 URL(有效期建议 ≤ 5–10 分钟);
-
签名必须包含不可预测因子(如
expires时间戳 +id+ 秘钥),避免 token 被推测复用; -
禁用目录遍历风险:
$file->link必须经白名单校验或使用realpath()+in_array()限定根目录; - 生产环境务必启用 HTTPS:Token 在明文 HTTP 中传输等于无效;
- 如需更高安全性,可结合 IP 绑定、单次使用(one-time token)或 CDN 鉴权(如 AWS CloudFront signed URLs / Cloudflare Access)。
通过该方案,你既保留了 <audio src="..."></audio> 的原生播放体验,又彻底切断了“复制链接即下载”的漏洞路径——这才是现代音视频服务应有的安全基线。



















