- Signed URL là gì
- Vì sao không nên chỉ dùng token random
- Nguyên tắc tạo signed URL an toàn
- Cấu trúc link mẫu
- Hàm tạo signed URL
- Ví dụ tạo link tải file
- Hàm kiểm tra signed URL
- Sử dụng trong file download.php
- Vì sao phải dùng hash_equals
- Signed URL dùng được cho những trường hợp nào
- Những sai lầm cần tránh
- Kết luận
Signed URL là gì
Signed URL là một đường link chứa:
- Dữ liệu cần truy cập (ví dụ: đường dẫn file)
- Thời gian hết hạn
- Chữ ký (signature) được tạo bằng secret key
Server sẽ kiểm tra chữ ký và thời gian. Sai hoặc hết hạn → từ chối ngay.
Vì sao không nên chỉ dùng token random
Nhiều hệ thống tạo link kiểu:
download.php?token=abcxyz
Vấn đề:
- Phải lưu token vào database
- Dọn token hết hạn rất mệt
- Leak database là đi luôn
Signed URL không cần lưu DB, chỉ cần secret key.
Nguyên tắc tạo signed URL an toàn
- Secret key chỉ tồn tại ở server
- Chữ ký phải dựa trên toàn bộ dữ liệu quan trọng
- Luôn có timestamp hết hạn
- Dùng hash mạnh như HMAC-SHA256
Cấu trúc link mẫu
Một signed URL thường trông như sau:
download.php?file=report.pdf&expires=1735689600&signature=xxxxx
Hàm tạo signed URL
<?php
function generate_signed_url(
string $baseUrl,
array $params,
int $expiresInSeconds,
string $secretKey
): string {
$expires = time() + $expiresInSeconds;
$params['expires'] = $expires;
ksort($params);
$queryString = http_build_query($params);
$dataToSign = $baseUrl . '?' . $queryString;
$signature = hash_hmac('sha256', $dataToSign, $secretKey);
return $dataToSign . '&signature=' . $signature;
}
Ví dụ tạo link tải file
<?php
$secretKey = 'super-secret-key';
$url = generate_signed_url(
'https://example.com/download.php',
['file' => 'invoices/2024.pdf'],
300, // 5 phút
$secretKey
);
echo $url;
Hàm kiểm tra signed URL
<?php
function verify_signed_url(
string $baseUrl,
array $params,
string $secretKey
): bool {
if (!isset($params['expires'], $params['signature'])) {
return false;
}
if ((int)$params['expires'] < time()) {
return false;
}
$signature = $params['signature'];
unset($params['signature']);
ksort($params);
$queryString = http_build_query($params);
$dataToSign = $baseUrl . '?' . $queryString;
$expectedSignature = hash_hmac('sha256', $dataToSign, $secretKey);
return hash_equals($expectedSignature, $signature);
}
Sử dụng trong file download.php
<?php
$secretKey = 'super-secret-key';
if (!verify_signed_url(
'https://example.com/download.php',
$_GET,
$secretKey
)) {
http_response_code(403);
die('Link không hợp lệ hoặc đã hết hạn');
}
$file = $_GET['file'];
// tiếp tục kiểm tra path an toàn rồi mới cho tải
Vì sao phải dùng hash_equals
hash_equals() giúp tránh timing attack. So sánh chuỗi bình thường có thể bị đo thời gian để đoán chữ ký.
Signed URL dùng được cho những trường hợp nào
- Link tải file riêng tư
- Link xem nội dung giới hạn thời gian
- Link reset mật khẩu
- Link xác nhận email
Những sai lầm cần tránh
- Đưa secret key ra frontend
- Ký thiếu tham số quan trọng
- Không kiểm tra expires
- Dùng hash yếu như md5
Kết luận
Signed URL là giải pháp nhẹ, sạch và rất hiệu quả cho các link cần kiểm soát truy cập. Không cần database, không cần cron dọn rác, chỉ cần một secret key và vài dòng PHP là đủ để nâng cấp bảo mật lên một tầm khác.
Link sống mãi là link nguy hiểm. Có hạn dùng mới là link đáng tin!
Bình luận