學習筆記:Pre-signed URL Level 1 — 核心心智模型

學習文章 · 2026-07-07 11:45
這是 pre-signed URL 學習路線圖的 Level 1,只鎖「核心心智模型」這一站。GET vs PUT、簽章的演算法細節(SigV4)怎麼算、.NET 怎麼寫、安全陷阱——那些是後面的站,這篇不碰。這篇的目標很單純:讓你能用白話跟同事講清楚「這條網址憑什麼能存取私有物件、卻不用登入、不用給密碼」。

零基礎先備:先認識幾個詞(S3 / bucket / 物件 / 私有 / HTTP 請求 / 憑證)

如果你沒碰過雲端的「物件儲存」,先花 30 秒把這幾個詞的白話意思裝進腦袋,後面才站得住:

還有兩個貫穿全文、先記著就好的詞:

好,帶著這幾個詞,我們來看那條「魔法網址」。

畫面是這樣:你手上有一個放在私有 bucket 裡的檔案 photo.jpg,直接把它的網址丟到瀏覽器——被擋,403。可是你用程式「簽」出另一條長長的網址,貼給一個完全沒有你們雲端帳號、沒有任何權限的同事,他點下去,檔案就下載下來了。

沒有登入、沒有交出密碼、沒改任何權限設定。這條網址到底施了什麼魔法?這一站就是要把這個魔法拆給你看。它其實一點都不玄——你讀完會發現它就是「一個先簽好名的 HTTP 請求」

就愛考你

這幾題就是本文的重點,也是讀完你該能用自己的話答出來的問題。先想想現在答不答得出來,然後帶著它們往下讀——遇到答案所在的段落就特別留意;讀完再回來點「看答案」對照。

  1. 為什麼一條 pre-signed URL 不用登入、也沒把密碼給對方,S3 卻願意把私有檔案給拿網址的人?看答案收合
    因為「身分證明」已經被算成一段簽章,跟著網址一起走了——這條 URL 本身就等於一個「先簽好名的 HTTP 請求」。
    • 平常打 S3 是一個帶憑證的 HTTP 請求;pre-signed URL 把「該長什麼樣的請求」整包壓進網址的 query string? 後面那串),再附上一段用你憑證算出的簽章。
    • 精確說:網址裡帶了你帳號的公開識別碼(等於帳號那半),但沒有帶密碼;真正的秘密早被壓成那段簽章。就像一張已簽名蓋章的取件單,櫃檯驗章即可,不問本人。
  2. 如果不用 pre-signed URL,要讓外人下載一個私有檔,你有哪些選項?它們各痛在哪?pre-signed URL 又好在哪?看答案收合
    三個爛選項:把物件公開(人人可看、難收回)、改 bucket policy(動整個櫃子的權限設定、易錯、難精準到單檔單人限時)、把密碼給對方(等於交出萬能鑰匙)。
    • pre-signed URL 一次解掉:對方零憑證限時自動失效範圍只限簽的那一件事
    • 而你這邊:不用公開、不用改權限設定、不用外洩密碼。
  3. 「pre-signed URL 是 bearer token」是什麼意思?這個性質對你保管它有什麼要求?看答案收合
    bearer token=「持有即有效」:它不認人,只認「你手上有沒有這張令牌」。像不記名門票,誰撿到誰能進場。
    • 結論:它是秘密,要當密碼一樣保護——別貼公開頻道、別寫進 log。
    • 一旦外洩,在到期前任何撿到的人都能做那條 URL 允許的動作。這也是「期限要短」的理由:令牌越短命,撿到越快作廢。
  4. 有人擔心「這條網址這麼萬能,會不會被拿去存取別的資源」。為什麼不會?它的權限天花板是什麼?看答案收合
    因為它的能力受限於「簽它的那組憑證」的權限——簽的人有多大權限,URL 頂多就那麼大,不會多一分。
    • 簽的人沒有某 bucket 權限,為它簽的 URL 一用就 403;只有讀權限卻簽了 PUT(上傳)的 URL,也一樣被擋。
    • 關鍵直覺:它不會放大權限,只是把你已有的權限切一小片(單物件/單動作/限時)轉授出去,切片不可能比原本大。
  5. 「能簽出一條 URL」跟「這條 URL 用得成」是同一件事嗎?為什麼會出現「簽出來看起來正常、對方一用卻 403」?看答案收合
    不是同一件事。任何有有效憑證的人都能「簽」出語法正確的 URL;但要「用得成」,簽它的那組憑證得在被使用當下真的有那個操作權限。
    • 簽的動作本身不檢查你有沒有權限——所以你能簽出一條漂亮但沒用的 URL。
    • 對方一用就 403,常見主因就是「簽的人其實沒有 s3:GetObject(S3「讀取物件」權限的正式名稱)之類的權限」。記住:能簽 ≠ 簽了有用
  6. 產生一條 pre-signed URL 的時候,你的程式需要連到 S3 嗎?那「檢查」到底在什麼時候、由誰做?看答案收合
    產生不連 S3——它是一次純本機的數學運算(拿你的密碼對請求參數做一次簽章運算,算出簽章拼成網址)。驗證發生在「別人真的拿 URL 去存取物件的那一刻」,由 S3/MinIO 執行。
    • 佐證:AWS 的官方文件列出「建立時只要提供憑證並指定 bucket/key/動作(下載/上傳…)/期限」,這串全是本機輸入、沒一步去問 S3;且 AWS 對比指出另一種發臨時憑證的做法「每產一組憑證都要打一次 API(=連到遠端服務跑一趟、要等它回話)」,presigned 則不必為此打 API。
    • 驗證時 S3 用網址參數重算一次簽章比對、檢查是否過期、憑證此刻是否仍有效有權限——全過才給檔。
    • (誠實補:AWS 對 S3「零連線」沒有逐字白紙黑字,此點以官方輸入清單+臨時憑證對比+Cloudflare R2 明文為據。)
  7. 綜合題:同事問你「這條網址憑什麼能下載私有檔、卻不用登入」,請用一段話完整回答(要點到簽章、bearer token、權限天花板)。看答案收合
    「這條網址不用登入,是因為身分已經被算成一段簽章跟著網址走了(網址帶的是帳號的公開識別碼,不是密碼);它是 bearer token,誰拿到誰能在期限內用;而且它能做的,絕不超過簽它的人本來的權限。」
    • 它=一個先簽好名的 HTTP 請求,帶著一段簽章與一個有效期限,整包壓進網址。
    • 它解決的問題:讓沒帳號的人限時存取私有檔,而你不用公開檔案/不用改權限設定/不用交出密碼。
    • 能講出這段,這一站就過關了。

一句話定義:它是「一個先簽好名、整包壓進網址裡的 HTTP 請求」

先給最精準的一句話,這句直接來自 AWS 官方:

pre-signed URL 是「一個被 IAM 認得的 HTTP 請求」。 它跟一般 AWS 請求的差別,在於它多帶了一個「有效期限」;而且跟其他需要驗證的請求一樣,它也帶著一段用你的憑證算出來的簽章

(IAM=AWS Identity and Access Management,是 AWS 的身分/權限管理系統,可以想成 AWS 的「門禁系統」——誰是誰、能做什麼,都它在管。這是本文第一次、也幾乎是唯一需要記住的專有名詞。)

這句話拆開來看,關鍵是三個詞:HTTP 請求、期限、簽章

比喻:它像一張「已經簽名蓋章的取件單」。 你不需要本人到場、不需要出示證件;單子上寫死了「憑此單、在 X 月 X 日前、可領走 3 號櫃第 5 格的東西」,還蓋了只有你能蓋的防偽章。櫃檯驗章沒問題、也還沒過期,就把東西給拿單子的人。單子本身就是通行證,不是你的身分。

這就回答了開頭的魔法:那條網址不需要「登入」,因為它自己就是一個簽好名的請求。身分證明已經被壓縮成那段簽章,跟著網址一起走了。

先打一劑預防針,免得你之後拆解網址時看到裡面的內容嚇一跳:嚴格說,網址裡其實帶了你帳號的公開識別碼(等於帳號那半,本來就不是秘密)。但它沒有帶密碼——真正的秘密(那把 secret key)從頭到尾沒出現在網址裡,它的效力早被壓縮成那段簽章。所以「不用登入、不用把密碼給對方」這個鉤子成立;只是別誤會成「網址裡什麼身分資訊都沒有」。

它解決什麼問題:讓沒帳號的人也能限時存取私有檔,而你什麼都不用交出去

沒有 pre-signed URL 的話,要讓外人存取一個私有物件,你的選項都很痛:

pre-signed URL 把這三個痛點一次解掉。AWS 官方對它的定位是:

你可以用 pre-signed URL 在不更新 bucket 權限設定的前提下,授予對某個物件「限時」的存取權。上傳方向也一樣——它讓別人可以上傳一個指定物件,而不需要對方擁有任何 AWS 帳密或權限

翻成白話,它同時做到三件別的方法做不到的事:

而你這邊,不用公開物件、不用改 bucket 權限設定、不用外洩密碼。三個痛點全避開了。

它本質是 bearer token:誰拿到、誰就有效,所以要當秘密保護

這是整站最重要的一個觀念,請一定記住。AWS 官方原話:

pre-signed URL 本質上就是 bearer token,會把存取權授予「持有它的任何人」。因此我們建議你妥善保護它。

「bearer token」直譯是「持有者令牌」——持有即有效。它不認人,只認「你手上有沒有這張令牌」。

比喻:它像一張不記名的演唱會門票。 票上不印你的名字,驗票員只看你手上有沒有這張票。你把票掉了、被撿走了、拍照發到群組被人存下來了——撿到/存到的人都能直接進場,門口不會問「你是不是本人」。

這個性質帶出一個你必須內化的結論:pre-signed URL 是秘密,要當密碼一樣保護。

權限天花板 = 產生者的權限:URL 能做的,絕不超過簽它那組憑證被允許的範圍

很多人第一次接觸會擔心:「這條網址這麼萬能,會不會被拿去存取別的東西、搞破壞?」不會。因為它有一道硬天花板。AWS 官方原話:

pre-signed URL 的能力,受限於「產生它的那個 user 的權限」

AWS 的最佳實務指南講得更死:

一條先簽好的請求只能允許「簽它的那組憑證本來就被允許的動作」。如果那組憑證(不管是明示或隱含地)禁止了該動作,這個請求送出去時就會被拒絕。

白話說:簽名的人有多大權限,這條 URL 頂多就那麼大,不會多一分。

關鍵直覺:pre-signed URL 不會「放大」權限,只會「轉授並限縮」你已有的權限。 它把你的權限切出一小片(單一物件、單一動作、限定時間),包成一條網址交出去。切出來的片,絕不可能比原本那塊大。

誰能「產」vs 誰能「用得成」:兩件不同的事

這兩件事常被混在一起,分清楚就通了。AWS 官方原話:

任何有有效憑證的人都能產生一條 pre-signed URL。 但要讓別人能「成功存取」那個物件,這條 URL 必須是由「真的有權限執行該操作的人」簽出來的。

拆成兩層:

所以會出現一種很常見的坑:你能簽出一條看起來完全正常的 URL,對方一用卻 403。 原因通常就是「簽的人其實沒有 s3:GetObject 之類的權限」——語法對,但天花板是零。(AWS 的常見問題明確把「產生 URL 的人必須有 s3:GetObject 等權限」列為 403 的頭號原因。)

一句話記住:「能簽」不等於「簽了有用」。 有效憑證就能簽;但要有用,簽的人得真的有那個權限。

產生是純本機運算,不連 S3;驗證才在物件被存取時發生

最後一個心智模型,也很反直覺:產生一條 pre-signed URL,過程中根本不需要連到 S3/MinIO。

它就是一次本機的數學運算——拿你手上的密碼(那把 secret key),對「請求的各項參數」做一次簽章運算,算出那段簽章,然後把結果拼成網址。整個過程你的機器沒有跟 S3 說過任何一句話。

怎麼確定?先看 AWS 自家官方文件怎麼描述「建立一條 pre-signed URL」需要哪些輸入:

建立 pre-signed URL 時,你要提供自己的憑證,然後指定:一個 S3 bucket、一個 object key、一個動作(下載/上傳/讀檔案的基本資訊…)、以及一段有效期限。

注意看:這一串全是你手邊就有的輸入——憑證、bucket 名、物件 key、動作、期限,沒有任何一步是去問 S3。這就是 AWS 自家(非第三方)對「產生是本機的事」的間接佐證。

再看 AWS 拿它跟「另一種發臨時憑證的做法」(AWS 有個叫 STS 的服務專門發臨時憑證)做的對比:

(用臨時憑證的做法)每產生一組憑證都需要打一次 API(打 API=連到遠端服務跑一趟、要等它回話),這會增加延遲、也多一個依賴……而先簽好的請求可以支援更短的期限(在對的條件下,60 秒都可行)。

換句話說,那條路每次都要打一趟 API;而 pre-signed URL 這條路是靠本機算簽章,不必為此打 API。Cloudflare R2 的官方文件把這件事講得最直白(它實作的是同一套 S3 標準):

產生 pre-signed URL 時完全不會跟 R2 通訊,你只需要你的 API 憑證,加上一份簽章演算法的實作。

那「檢查」發生在哪?發生在別人真的拿這條 URL 去存取物件的那一刻。這時 S3/MinIO 才會出場,用網址裡的參數重新算一次簽章跟網址上那段簽章比對、檢查有沒有過期、簽它的憑證此刻是否仍有效且有權限——全部通過,才把物件給你。

一句話分清兩端:簽名(產生)是「發送方本機的事」,驗證(檢查)是「S3 收到請求時的事」。 兩者在不同時間、不同地點發生。這也解釋了為什麼你能「離線」預先簽一大把 URL,而它們要等到真的被用時、才由 S3 去判生死。

(精確補一句:簽章在數學上只需要你的密碼與請求參數,本就是純本機計算;上面的官方輸入清單、臨時憑證對比與 R2 明文都支持「產生不連 store」。若要一句 AWS 官方對 S3「零連線」的白紙黑字,我在這次爬過的頁面裡沒找到逐字版本,故此點以上述幾項為據。)

收尾:一口氣把六件事串起來

如果同事問你「這條網址憑什麼?」,你現在應該能一口氣講完——講得出下面這六點,這一站就過關了

  1. 它是一個先簽好名的 HTTP 請求,帶著一段簽章與一個有效期限,整包壓進網址;網址裡帶的是帳號的公開識別碼,不是密碼。
  2. 它讓沒帳號沒權限的人也能限時存取私有物件,而你不用公開檔案、不用改 bucket 權限設定、不用交出密碼。
  3. 它是 bearer token——持有即有效,所以要當秘密保護。
  4. 它的權限天花板就是簽它那組憑證的權限,不會多一分。
  5. 有效憑證就能「簽」,但要「用得成」得簽的人真的有那個權限——能簽不等於簽了有用。
  6. 簽是純本機運算、不連 S3;驗證才在物件被存取時由 S3 執行。

下一站(Level 2)我們再分「下載該用 GET、上傳該用 PUT」,以及瀏覽器怎麼直接把檔案傳上 S3。

參考來源(實際爬過的權威連結)