URL ký trước của S3 là một liên kết tạm thời tới một đối tượng trong bucket riêng tư. Nó mang chữ ký trong chuỗi truy vấn, nên ai giữ nó đều có thể tải xuống (hoặc tải lên) đối tượng đó mà không cần thông tin đăng nhập AWS cho tới khi liên kết hết hạn, và bucket không bao giờ trở thành công khai. Bạn tạo nó bằng khóa của chính mình, trong mã hoặc từ AWS CLI, và nó có thể kéo dài từ 1 giây đến 7 ngày. Hướng dẫn này giải thích cách nó hoạt động, ý nghĩa của từng tham số X-Amz-*, nó có thể kéo dài bao lâu, mã cho tải xuống và tải lên, và những lỗi bạn dễ gặp nhất. Các giới hạn được lấy từ tài liệu của AWS và Cloudflare tính đến tháng 10 năm 2026.
Tóm tắt về URL ký trước S3
| Câu hỏi | Trả lời |
|---|---|
| Nó cấp quyền gì? | Một thao tác (GET, PUT, HEAD, DELETE…) trên một đối tượng |
| Thời hạn tối đa | 7 ngày (604.800 giây) với SigV4 và khóa người dùng IAM |
| Thời hạn với khóa tạm thời | Kết thúc khi phiên role hoặc thông tin STS kết thúc, tùy điều kiện nào đến trước |
| Phạm vi trong S3 console | 1 phút đến 12 giờ |
| Thời hạn mặc định | 3.600 giây trong AWS CLI và boto3, 900 giây trong presigner JavaScript v3 |
| Có thể dùng nhiều lần không? | Có, bao nhiêu lần tùy thích cho tới khi hết hạn |
| Có thể thu hồi một URL không? | Không, chỉ bằng cách thu hồi thông tin đăng nhập đã ký hoặc từ chối trong policy |
| Tạo URL có gọi tới S3 không? | Không, chữ ký được tính cục bộ |
URL ký trước hoạt động thế nào
- Mã của bạn (hoặc CLI) lấy bucket, khóa đối tượng, phương thức HTTP và thời hạn.
- SDK ký các giá trị đó bằng secret access key của bạn theo AWS Signature Version 4. Lúc này chưa có gì được gửi tới S3.
- Bạn đưa URL nhận được cho ai đó: một trình duyệt, một đồng nghiệp, một ứng dụng di động.
- Khi họ dùng nó, S3 tính lại chữ ký bằng secret thuộc access key trong URL. Nếu chữ ký khớp, URL chưa hết hạn và người ký được phép thực hiện thao tác đó, yêu cầu sẽ được chấp nhận.
URL mang quyền của người đã ký nó. AWS nói rõ điều này: nếu người dùng IAM hoặc role tạo URL không đọc được đối tượng, URL sẽ trả về 403 dù chữ ký có hợp lệ đến đâu.
Ý nghĩa của các tham số X-Amz
Một URL ký trước SigV4 trông như thế này (đã thêm xuống dòng):
https://my-bucket.s3.eu-west-1.amazonaws.com/reports/q3.pdf
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20261017%2Feu-west-1%2Fs3%2Faws4_request
&X-Amz-Date=20261017T093000Z
&X-Amz-Expires=3600
&X-Amz-SignedHeaders=host
&X-Amz-Signature=5f2c...e91a
| Tham số | Ý nghĩa |
|---|---|
X-Amz-Algorithm | Thuật toán ký: AWS4-HMAC-SHA256 với SigV4 |
X-Amz-Credential | Access key ID cùng phạm vi: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request |
X-Amz-Date | Thời điểm URL được ký, theo UTC, yyyyMMddTHHmmssZ |
X-Amz-Expires | Số giây URL còn hiệu lực sau X-Amz-Date, từ 1 đến 604800 |
X-Amz-SignedHeaders | Các header được chữ ký bao gồm, luôn có ít nhất host |
X-Amz-Signature | Chữ ký, 64 ký tự thập lục phân |
X-Amz-Security-Token | Chỉ có khi URL được ký bằng thông tin đăng nhập tạm thời (STS, role, EC2, ECS, SSO) |
Thay đổi bất kỳ phần nào đã được ký (khóa, phương thức, thời hạn hoặc một header đã ký) thì chữ ký sẽ không còn khớp. Cũng lưu ý những gì URL để lộ dưới dạng văn bản thuần: tên bucket, khóa đầy đủ của đối tượng và access key ID của bạn. Secret key không bao giờ nằm trong URL.
URL ký trước kéo dài bao lâu
Giới hạn phụ thuộc vào thông tin đăng nhập dùng để ký:
| Ký bằng | Hiệu lực tối đa |
|---|---|
| Access key của người dùng IAM (SigV4) | 7 ngày, vì bản thân khóa ký SigV4 có hiệu lực 7 ngày |
| Phiên role IAM (STS AssumeRole) | Cho tới khi phiên kết thúc, mặc định 1 giờ |
| EC2 instance profile | Cho tới khi thông tin của role được xoay vòng, tối đa khoảng 6 giờ |
| ECS task role | Cho tới khi thông tin của task được xoay vòng, thường mỗi 1 đến 6 giờ |
| Mọi thông tin đăng nhập bị thu hồi hoặc xóa | Dừng ngay lập tức, bất kể X-Amz-Expires ghi gì |
| S3 console | Bạn chọn từ 1 phút đến 12 giờ |
Điều này giải thích bất ngờ phổ biến nhất: bạn yêu cầu 7 ngày từ một hàm Lambda hoặc một EC2 instance và liên kết chết sau một giờ hoặc vài giờ. URL chỉ sống lâu bằng thông tin đăng nhập đứng sau nó. Nếu bạn cần liên kết dài hạn, hãy ký bằng một người dùng IAM riêng chỉ có quyền đọc bucket đó.
S3 kiểm tra thời hạn khi yêu cầu bắt đầu. Một lượt tải xuống lớn bắt đầu một giây trước hạn chót vẫn hoàn tất bình thường, nhưng một lần thử lại sau hạn chót sẽ thất bại với AccessDenied và thông báo “Request has expired”. Yêu cầu hơn 604.800 giây sẽ bị từ chối ngay.
Cách tạo URL ký trước
AWS CLI
aws s3 presign s3://my-bucket/reports/q3.pdf --expires-in 3600
Lệnh này ký một URL tải xuống (GET). Mặc định là 3.600 giây và tối đa 604.800. Các phiên bản CLI gần đây luôn dùng SigV4, nên hãy đảm bảo đã cấu hình khu vực. Với URL tải lên, bạn cần một SDK.
Python (boto3)
import boto3
from botocore.config import Config
s3 = boto3.client('s3', region_name='eu-west-1', config=Config(signature_version='s3v4'))
url = s3.generate_presigned_url(
ClientMethod='get_object',
Params={
'Bucket': 'my-bucket',
'Key': 'reports/q3.pdf',
'ResponseContentDisposition': 'attachment; filename="q3.pdf"',
},
ExpiresIn=3600,
)
Hãy đặt signature_version='s3v4' một cách rõ ràng. Tài liệu tham khảo của boto3 cảnh báo rằng, vì lý do tương thích ngược, nếu không đặt thì nó có thể ký bằng Signature Version 2 cũ hơn ở những khu vực vẫn chấp nhận, và âm thầm bỏ qua một số tham số và header như Range. ResponseContentDisposition là tùy chọn: nó khiến trình duyệt lưu tệp với tên gọn gàng thay vì mở trực tiếp.
JavaScript (AWS SDK v3)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
const client = new S3Client({ region: 'eu-west-1' })
const url = await getSignedUrl(
client,
new GetObjectCommand({ Bucket: 'my-bucket', Key: 'reports/q3.pdf' }),
{ expiresIn: 3600 }
)
Nếu bạn bỏ qua expiresIn, presigner JavaScript dùng 900 giây (15 phút).
URL tải lên ký trước (PUT)
Ý tưởng tương tự hoạt động theo chiều ngược lại. Bạn ký một PutObject cho một khóa và ai có URL đều có thể ghi đối tượng đó. Tệp đi thẳng từ thiết bị của họ vào bucket và máy chủ của bạn không bao giờ xử lý các byte. Nếu đã có đối tượng với khóa đó, nó sẽ bị thay thế.
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
const client = new S3Client({ region: 'eu-west-1' })
const url = await getSignedUrl(
client,
new PutObjectCommand({
Bucket: 'my-bucket',
Key: 'incoming/brief.pdf',
ContentType: 'application/pdf',
}),
{ expiresIn: 900, signableHeaders: new Set(['content-type']) }
)
await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/pdf' },
body: file,
})
Thêm content-type vào signableHeaders sẽ ràng buộc URL với loại đó, nên một lần tải lên với Content-Type khác sẽ bị từ chối. Trong boto3, cách tương đương là generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), và client phải gửi cùng header đó.
Ba điều cần kiểm tra trước khi tải lên từ trình duyệt:
- CORS. Bucket cần một quy tắc CORS cho phép origin của bạn và phương thức
PUT. Với tải lên multipart, nó cũng phải hiển thị headerETag, vì trình duyệt phải đọc header này từ mỗi phần. - Khóa cố định. Tạo một khóa duy nhất trên máy chủ (ví dụ với tiền tố UUID) để khách truy cập không thể ghi đè tệp của người khác.
- Checksum. Các AWS SDK hiện tại mặc định thêm checksum CRC vào lần tải lên. Nếu tải lên ký trước thất bại với một nhà cung cấp tương thích S3 do lỗi chữ ký hoặc checksum, hãy đặt
requestChecksumCalculation: 'WHEN_REQUIRED'trên client.
POST ký trước là một cơ chế riêng cho biểu mẫu HTML thuần, với một policy có thể giới hạn kích thước và loại nội dung. Không phải nhà cung cấp tương thích S3 nào cũng hỗ trợ nó (R2 không hỗ trợ), nên PUT ký trước là lựa chọn dễ chuyển đổi hơn.
Tệp lớn: tải lên multipart ký trước
Một lần PUT vào S3 bị giới hạn ở 5 GB, và AWS khuyên dùng multipart từ khoảng 100 MB. Multipart chia tệp thành tối đa 10.000 phần, mỗi phần từ 5 MiB đến 5 GiB trừ phần cuối, được tải lên độc lập, song song và thử lại theo từng phần. Việc ký trước hoạt động theo từng phần: máy chủ bắt đầu lần tải lên, ký một URL UploadPart cho mỗi phần, trình duyệt gửi từng khối và báo lại ETag của nó, rồi máy chủ hoàn tất lần tải lên.
import {
CreateMultipartUploadCommand,
UploadPartCommand,
CompleteMultipartUploadCommand,
} from '@aws-sdk/client-s3'
const { UploadId } = await client.send(
new CreateMultipartUploadCommand({ Bucket: 'my-bucket', Key: 'video/raw.mov' })
)
const partUrl = await getSignedUrl(
client,
new UploadPartCommand({ Bucket: 'my-bucket', Key: 'video/raw.mov', UploadId, PartNumber: 1 }),
{ expiresIn: 3600 }
)
await client.send(
new CompleteMultipartUploadCommand({
Bucket: 'my-bucket',
Key: 'video/raw.mov',
UploadId,
MultipartUpload: { Parts: [{ PartNumber: 1, ETag: etagFromPartResponse }] },
})
)
Hãy thêm một quy tắc vòng đời hủy các lần tải lên multipart chưa hoàn tất sau vài ngày, nếu không các phần bị bỏ dở sẽ tiếp tục chiếm dung lượng lưu trữ bị tính phí.
URL ký trước trên R2, B2, Spaces và Wasabi
Các nhà cung cấp triển khai API S3 với SigV4 chấp nhận cùng một đoạn mã: bạn chỉ thay endpoint, khu vực và khóa. Chi tiết có khác nhau, nên hãy kiểm tra tài liệu của nhà cung cấp:
- Cloudflare R2 hỗ trợ
GET,HEAD,PUTvàDELETEký trước, với thời hạn từ 1 giây đến 7 ngày. Nó không hỗ trợPOSTký trước, và URL ký trước chỉ hoạt động trên tên miền API S3 (<ACCOUNT_ID>.r2.cloudflarestorage.com), không phải trên tên miền tùy chỉnh. Dùngregion: 'auto'. - Backblaze B2 cho biết API tương thích S3 của họ hỗ trợ URL ký trước tạo bằng AWS CLI hoặc SDK.
- DigitalOcean Spaces và Wasabi hoạt động với cùng các lệnh gọi SDK trỏ tới endpoint của họ.
Về giá của từng nhà cung cấp, xem so sánh S3, R2, Spaces, Wasabi và B2.
Các lỗi URL ký trước thường gặp và cách sửa
| Lỗi | Nguyên nhân thường gặp | Cách sửa |
|---|---|---|
SignatureDoesNotMatch | Phương thức, header hoặc truy vấn khác với những gì đã ký; đồng hồ bị lệch | Gửi cùng Content-Type và header; đồng bộ đồng hồ bằng NTP |
AccessDenied “Request has expired” | URL đã quá X-Amz-Date + X-Amz-Expires | Tạo URL mới; rút ngắn khoảng thời gian giữa lúc ký và lúc dùng |
| URL hết hạn sớm hơn yêu cầu | Ký bằng thông tin đăng nhập tạm thời (role, EC2, ECS, Lambda) | Ký bằng thông tin đăng nhập sống lâu bằng thời hạn liên kết cần có |
ExpiredToken | Phiên STS đứng sau X-Amz-Security-Token đã kết thúc | Làm mới thông tin đăng nhập trước khi ký |
403 AccessDenied với URL mới tạo | Người ký thiếu s3:GetObject hoặc s3:PutObject, hoặc một policy từ chối | Cấp quyền cho chủ thể ký; kiểm tra bucket policy |
AuthorizationQueryParametersError | Thời hạn trên 604.800 giây hoặc phạm vi credential sai định dạng | Giữ X-Amz-Expires ở mức 7 ngày hoặc ít hơn; ký trong khu vực của bucket |
| Trình duyệt bị CORS chặn | Bucket không có quy tắc CORS cho origin và phương thức của bạn | Thêm quy tắc CORS với origin của bạn, GET/PUT và hiển thị ETag |
AccessDenied với HeadersNotSigned | Range đã được ký nhưng If-Range được gửi mà không ký | Thêm If-Range vào các header được ký |
Proxy doanh nghiệp viết lại header hoặc chuỗi truy vấn cũng làm hỏng chữ ký. Nếu một URL hoạt động từ mạng này mà không hoạt động từ mạng khác, hãy thử không qua proxy.
Các phương pháp bảo mật tốt nhất
AWS gọi URL ký trước là bearer token và khuyến nghị bảo vệ chúng. Trên thực tế:
- Giữ chúng ngắn. Vài phút cho tải lên và tệp nhạy cảm, vài giờ cho tải xuống thông thường. Tạo URL mới khi ai đó cần tệp lần nữa.
- Ký bằng một danh tính có phạm vi hẹp. Một người dùng IAM hoặc role riêng chỉ có thể đọc (hoặc chỉ ghi) tiền tố liên quan sẽ hạn chế thiệt hại nếu liên kết bị lộ.
- Thêm rào chắn trong bucket policy. Điều kiện
s3:signatureAgetừ chối chữ ký cũ hơn một độ tuổi nhất định, vàaws:SourceIpgiới hạn những mạng có thể dùng chúng. - Đừng ghi chúng vào log. URL ký trước đầy đủ trong log ứng dụng, phân tích hay lịch sử trò chuyện là thông tin đăng nhập còn hiệu lực cho tới khi hết hạn.
- Lường trước những gì chúng thiếu. Không có mật khẩu, không đếm lượt tải xuống và không thu hồi theo từng liên kết, nên hãy đặt một ứng dụng ở phía trước khi bạn cần những thứ đó.
Để tìm hiểu sâu về khía cạnh chia sẻ, với các lựa chọn bổ sung những kiểm soát đó, xem cách chia sẻ tệp S3 mà không cần công khai bucket.
Nubbo dùng URL ký trước thế nào
Nubbo được xây dựng trên mô hình này. Khi bạn tải lên trong trình khám phá, máy chủ ký một PUT (hoặc, từ 100 MB, một lần tải lên multipart với ba phần song song) và trình duyệt của bạn gửi các byte thẳng tới bucket. Tải xuống từng tệp dùng URL GET ký trước có hiệu lực một giờ. Access key của bạn được lưu ở dạng mã hóa AES-256-GCM và chỉ được dùng trên máy chủ để ký.
Liên kết chia sẻ bổ sung những gì URL ký trước thuần túy thiếu: mật khẩu, ngày hết hạn và giới hạn lượt tải xuống tùy chọn mà Nubbo kiểm tra trước khi cấp một URL có thời hạn ngắn, và bạn có thể vô hiệu hóa liên kết bất cứ lúc nào. Tải xuống ZIP nhiều tệp được tạo ngay trong trình duyệt của bạn bằng cách tải từng tệp thẳng từ bucket của bạn: Nubbo không bao giờ thấy nội dung. Một ngoại lệ cần nói rõ: ảnh thu nhỏ được ghi vào chính bucket của bạn trong .nubbo-thumbs/. Mọi thứ hoạt động như nhau trên Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 và các endpoint tương thích S3 công khai.
Câu hỏi thường gặp
URL ký trước trong S3 là gì?
Đó là một liên kết HTTPS bình thường tới một đối tượng trong bucket riêng tư, có thêm chữ ký trong chuỗi truy vấn. Ai có liên kết đều có thể thực hiện đúng một thao tác mà nó được ký, thường là tải xuống (GET) hoặc tải lên (PUT), cho tới khi nó hết hạn. Bucket vẫn ở chế độ riêng tư và người dùng liên kết không cần thông tin đăng nhập AWS.
Thời hạn tối đa của URL ký trước S3 là bao lâu?
Bảy ngày (604.800 giây) khi bạn ký bằng Signature Version 4 và khóa dài hạn của người dùng IAM. Một URL ký bằng thông tin đăng nhập tạm thời, như một role được assume hoặc EC2 instance profile, ngừng hoạt động khi các thông tin đó hết hạn, kể cả khi bạn yêu cầu lâu hơn. Trong S3 console, bạn có thể chọn từ 1 phút đến 12 giờ.
X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders và X-Amz-Signature nghĩa là gì?
Đó là các tham số xác thực SigV4. Algorithm là phương thức ký (AWS4-HMAC-SHA256), Credential là access key ID cùng phạm vi ngày, khu vực và dịch vụ, Date là thời điểm URL được ký, Expires là số giây URL còn hiệu lực, SignedHeaders liệt kê các header được chữ ký bao gồm và Signature là chính chữ ký. X-Amz-Security-Token chỉ xuất hiện khi URL được ký bằng thông tin đăng nhập tạm thời.
Tôi có thể thu hồi một URL ký trước S3 trước khi nó hết hạn không?
Không thể thu hồi từng URL một. Một URL ký trước chỉ ngừng hoạt động sớm khi thông tin đăng nhập đã ký nó bị thu hồi, xóa hoặc vô hiệu hóa, hoặc khi một bucket policy từ chối yêu cầu. Nếu bạn cần hủy từng liên kết riêng lẻ, hãy đặt một ứng dụng ở phía trước chỉ cấp URL có thời hạn ngắn sau khi tự kiểm tra.
URL ký trước S3 có an toàn không?
Chữ ký không thể bị giả mạo hay sửa đổi, và bucket vẫn ở chế độ riêng tư. Nhưng AWS mô tả URL ký trước là bearer token: ai có liên kết đều có thể dùng nó, bao nhiêu lần tùy thích, cho tới khi hết hạn. Hãy giữ thời hạn ngắn, dùng HTTPS và tránh đăng liên kết ở nơi có thể bị sao chép.
URL ký trước có hoạt động với Cloudflare R2, Backblaze B2 hay Wasabi không?
Các nhà cung cấp triển khai API S3 với Signature Version 4 thường hỗ trợ chúng, và bạn dùng cùng các lệnh gọi SDK với endpoint của nhà cung cấp. Ví dụ Cloudflare R2 hỗ trợ GET, HEAD, PUT và DELETE ký trước với thời hạn từ 1 giây đến 7 ngày, nhưng không hỗ trợ tải lên qua biểu mẫu POST và không hỗ trợ tên miền tùy chỉnh.
Tại sao URL ký trước của tôi trả về SignatureDoesNotMatch?
AWS liệt kê ba nguyên nhân phổ biến: đồng hồ máy tính bị lệch, một proxy thay đổi header hoặc chuỗi truy vấn, và một yêu cầu có phương thức, header hoặc tham số khác với những gì đã được ký. Với tải lên, thủ phạm thường gặp là gửi Content-Type khác với Content-Type dùng khi tạo URL.
Nguồn
Giá và giới hạn lấy từ các trang chính thức bên dưới. Nhà cung cấp có thể thay đổi chúng, nên hãy kiểm tra trước khi quyết định.
- Amazon S3: tải xuống và tải lên đối tượng bằng URL ký trước
- AWS IAM: các phương thức xác thực (tham số truy vấn SigV4)
- API Amazon S3: xác thực yêu cầu bằng tham số truy vấn (SigV4)
- Tài liệu tham khảo AWS CLI: s3 presign
- Tài liệu tham khảo Boto3: generate_presigned_url
- AWS SDK for JavaScript v3: @aws-sdk/s3-request-presigner
- Amazon S3: giới hạn tải lên multipart
- AWS SDKs and Tools: bảo vệ toàn vẹn dữ liệu cho Amazon S3
- Cloudflare R2: URL ký trước
- Backblaze: API tương thích S3 của B2 có hỗ trợ URL ký trước không?