You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP服务端与客户端实现HLS流的Token安全机制?

HLS流Token签名验证实现方案(PHP服务端 + hls.js客户端)

核心原理

不管是wmsAuthSign还是signature,本质都是基于约定的密钥+请求参数生成哈希签名:客户端只能使用服务端签发的带签名URL请求流资源,服务端收到请求后重新计算签名并对比,验证合法性后才返回流文件。

一、服务端(PHP)实现签名生成

1. 定义签名规则

选择用于生成签名的核心参数(建议包含):

  • exp:URL过期时间戳(Unix时间,防止URL永久有效)
  • stream:唯一流ID(区分不同流资源)
  • ip:客户端IP(可选,绑定请求IP增强安全性)
  • 密钥SECRET_KEY:服务端保密密钥,绝对不能暴露给客户端

2. 生成带签名的播放URL代码示例

<?php
// 服务端专属保密密钥,自行替换为高强度字符串
define('SECRET_KEY', 'your_strong_secret_key_here');

/**
 * 生成带签名的HLS流URL
 * @param string $streamId 流唯一标识
 * @param int $expireSeconds URL有效期(秒,例:3600=1小时)
 * @param string|null $clientIp 绑定的客户端IP(可选)
 * @return string
 */
function generateSignedHlsUrl(string $streamId, int $expireSeconds = 3600, ?string $clientIp = null): string {
    // 计算过期时间戳
    $expire = time() + $expireSeconds;
    
    // 整理签名参数,按参数名排序避免顺序影响签名结果
    $params = [
        'stream' => $streamId,
        'exp' => $expire
    ];
    if ($clientIp) {
        $params['ip'] = $clientIp;
    }
    ksort($params);
    $rawString = http_build_query($params);
    
    // 生成HMAC-SHA256签名
    $signature = hash_hmac('sha256', $rawString, SECRET_KEY);
    
    // 拼接最终URL(替换为你的流基础地址)
    $baseUrl = "http://your-domain.com/hls/{$streamId}.m3u8";
    $signedUrl = $baseUrl . '?' . $rawString . '&signature=' . $signature;

    // 若需适配wmsAuthSign格式,可改为:
    // $wmsAuthSign = "wmsAuthSign=stream={$streamId}&exp={$expire}&signature={$signature}";
    // $signedUrl = $baseUrl . '?' . $wmsAuthSign;
    
    return $signedUrl;
}

// 示例:生成绑定当前客户端IP、有效期1小时的流URL
$signedUrl = generateSignedHlsUrl('live_stream_001', 3600, $_SERVER['REMOTE_ADDR']);
echo $signedUrl;
?>

二、服务端(PHP)实现签名校验

在处理HLS流文件(m3u8、ts)请求的PHP脚本中,添加校验逻辑:

<?php
define('SECRET_KEY', 'your_strong_secret_key_here');

/**
 * 校验HLS请求的签名合法性
 * @return bool
 */
function validateHlsSignature(): bool {
    // 提取URL参数
    $stream = $_GET['stream'] ?? '';
    $exp = $_GET['exp'] ?? 0;
    $signature = $_GET['signature'] ?? '';
    $clientIp = $_GET['ip'] ?? $_SERVER['REMOTE_ADDR'];
    
    // 1. 检查URL是否过期
    if (time() > (int)$exp) {
        return false;
    }
    
    // 2. 按生成时的规则重新拼接原始字符串
    $params = [
        'stream' => $stream,
        'exp' => $exp,
        'ip' => $clientIp
    ];
    ksort($params);
    $rawString = http_build_query($params);
    
    // 3. 重新计算签名并对比(用hash_equals防止时序攻击)
    $calculatedSignature = hash_hmac('sha256', $rawString, SECRET_KEY);
    return hash_equals($calculatedSignature, $signature);
}

// 校验不通过则返回403
if (!validateHlsSignature()) {
    http_response_code(403);
    exit('Forbidden: Invalid signature or expired URL');
}

// 校验通过,返回流文件(可改用nginx X-Accel-Redirect优化性能)
$streamPath = "/path/to/your/hls/files/{$_GET['stream']}.m3u8";
if (file_exists($streamPath)) {
    header('Content-Type: application/vnd.apple.mpegurl');
    readfile($streamPath);
} else {
    http_response_code(404);
    exit('Stream not found');
}
?>

三、客户端(hls.js)使用带签名的URL

客户端只需获取服务端生成的带签名URL,直接传入hls.js即可:

// 从服务端接口获取带签名的流URL
const signedHlsUrl = 'http://your-domain.com/hls/live_stream_001.m3u8?stream=live_stream_001&exp=1718xxxxxx&ip=192.168.1.100&signature=abcdef123456...';

const video = document.getElementById('hls-video');
const hls = new Hls();

hls.loadSource(signedHlsUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
    video.play();
});

关键注意事项

  • 密钥保密:SECRET_KEY必须仅在服务端存储,绝对不能出现在客户端代码中。
  • 参数一致性:生成和校验签名时的参数顺序、编码规则必须完全一致,否则校验会失败。
  • 强制过期:必须添加exp参数,避免URL被永久滥用。
  • 性能优化:高并发场景下,建议将校验逻辑迁移到Nginx层面(如Lua脚本),减少PHP性能开销。

内容的提问来源于stack exchange,提问作者amirhosein karimi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:46:39