Hàm tạo link tạm thời (signed URL) trong PHP

Không phải link nào cũng nên tồn tại mãi mãi. Link tải file, link xem nội dung riêng tư, link reset mật khẩu… nếu ai có được thì dùng vô thời hạn là toang bảo mật. Giải pháp gọn nhẹ, thực dụng: signed URL – link có chữ ký, có thời hạn, hết hạn là vô dụng.

Hàm tạo link tạm thời (signed URL) trong PHP

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


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...