學習筆記:Pre-signed URL Level 1 — 核心心智模型
學習文章 · 2026-07-07 11:45
這是 pre-signed URL 學習路線圖的 Level 1,只鎖「核心心智模型」這一站。GET vs PUT、簽章的演算法細節(SigV4)怎麼算、.NET 怎麼寫、安全陷阱——那些是後面的站,這篇不碰。這篇的目標很單純:讓你能用白話跟同事講清楚「這條網址憑什麼能存取私有物件、卻不用登入、不用給密碼」。
零基礎先備:先認識幾個詞(S3 / bucket / 物件 / 私有 / HTTP 請求 / 憑證)
如果你沒碰過雲端的「物件儲存」,先花 30 秒把這幾個詞的白話意思裝進腦袋,後面才站得住:
- S3:Amazon 的物件儲存服務——白話說就是「把檔案存在雲端的一個大倉庫」。(MinIO、Cloudflare R2 是相容的同類,用法幾乎一樣,本文說 S3 時它們也通。)
- bucket:倉庫裡的櫃子/容器,你的檔案就放在某個 bucket 裡面。
- 物件(object):存進去的一份檔案,用一個 key(就是它的路徑 + 檔名,例如
uploads/photo.jpg)來定位。
- 私有:這個櫃子預設不公開——直接把物件的網址丟到瀏覽器,會被擋下來(回你一個 403,意思是「禁止存取」)。
還有兩個貫穿全文、先記著就好的詞:
- HTTP 請求:你的程式對一個網路服務發出的一次操作要求,例如「下載這個檔案」「上傳這個檔案」。你平常瀏覽器打開網頁,背後也是在發 HTTP 請求。
- 憑證(credentials):你在雲端帳號的那組鑰匙——一半是公開識別碼(等於帳號,可以公開)、一半是只有你知道的密碼(就是 secret key,絕不能外流)。後面講的「公開識別碼/密碼/權限天花板」都是從這組鑰匙延伸出來的。
好,帶著這幾個詞,我們來看那條「魔法網址」。
畫面是這樣:你手上有一個放在私有 bucket 裡的檔案 photo.jpg,直接把它的網址丟到瀏覽器——被擋,403。可是你用程式「簽」出另一條長長的網址,貼給一個完全沒有你們雲端帳號、沒有任何權限的同事,他點下去,檔案就下載下來了。
沒有登入、沒有交出密碼、沒改任何權限設定。這條網址到底施了什麼魔法?這一站就是要把這個魔法拆給你看。它其實一點都不玄——你讀完會發現它就是「一個先簽好名的 HTTP 請求」。
就愛考你
這幾題就是本文的重點,也是讀完你該能用自己的話答出來的問題。先想想現在答不答得出來,然後帶著它們往下讀——遇到答案所在的段落就特別留意;讀完再回來點「看答案」對照。
-
為什麼一條 pre-signed URL 不用登入、也沒把密碼給對方,S3 卻願意把私有檔案給拿網址的人?看答案收合
因為「身分證明」已經被算成一段簽章,跟著網址一起走了——這條 URL 本身就等於一個「先簽好名的 HTTP 請求」。
- 平常打 S3 是一個帶憑證的 HTTP 請求;pre-signed URL 把「該長什麼樣的請求」整包壓進網址的 query string(
? 後面那串),再附上一段用你憑證算出的簽章。
- 精確說:網址裡帶了你帳號的公開識別碼(等於帳號那半),但沒有帶密碼;真正的秘密早被壓成那段簽章。就像一張已簽名蓋章的取件單,櫃檯驗章即可,不問本人。
-
如果不用 pre-signed URL,要讓外人下載一個私有檔,你有哪些選項?它們各痛在哪?pre-signed URL 又好在哪?看答案收合
三個爛選項:把物件公開(人人可看、難收回)、改 bucket policy(動整個櫃子的權限設定、易錯、難精準到單檔單人限時)、把密碼給對方(等於交出萬能鑰匙)。
- pre-signed URL 一次解掉:對方零憑證、限時自動失效、範圍只限簽的那一件事。
- 而你這邊:不用公開、不用改權限設定、不用外洩密碼。
-
「pre-signed URL 是 bearer token」是什麼意思?這個性質對你保管它有什麼要求?看答案收合
bearer token=「持有即有效」:它不認人,只認「你手上有沒有這張令牌」。像不記名門票,誰撿到誰能進場。
- 結論:它是秘密,要當密碼一樣保護——別貼公開頻道、別寫進 log。
- 一旦外洩,在到期前任何撿到的人都能做那條 URL 允許的動作。這也是「期限要短」的理由:令牌越短命,撿到越快作廢。
-
有人擔心「這條網址這麼萬能,會不會被拿去存取別的資源」。為什麼不會?它的權限天花板是什麼?看答案收合
因為它的能力受限於「簽它的那組憑證」的權限——簽的人有多大權限,URL 頂多就那麼大,不會多一分。
- 簽的人沒有某 bucket 權限,為它簽的 URL 一用就 403;只有讀權限卻簽了 PUT(上傳)的 URL,也一樣被擋。
- 關鍵直覺:它不會放大權限,只是把你已有的權限切一小片(單物件/單動作/限時)轉授出去,切片不可能比原本大。
-
「能簽出一條 URL」跟「這條 URL 用得成」是同一件事嗎?為什麼會出現「簽出來看起來正常、對方一用卻 403」?看答案收合
不是同一件事。任何有有效憑證的人都能「簽」出語法正確的 URL;但要「用得成」,簽它的那組憑證得在被使用當下真的有那個操作權限。
- 簽的動作本身不檢查你有沒有權限——所以你能簽出一條漂亮但沒用的 URL。
- 對方一用就 403,常見主因就是「簽的人其實沒有
s3:GetObject(S3「讀取物件」權限的正式名稱)之類的權限」。記住:能簽 ≠ 簽了有用。
-
產生一條 pre-signed URL 的時候,你的程式需要連到 S3 嗎?那「檢查」到底在什麼時候、由誰做?看答案收合
產生不連 S3——它是一次純本機的數學運算(拿你的密碼對請求參數做一次簽章運算,算出簽章拼成網址)。驗證發生在「別人真的拿 URL 去存取物件的那一刻」,由 S3/MinIO 執行。
- 佐證:AWS 的官方文件列出「建立時只要提供憑證並指定 bucket/key/動作(下載/上傳…)/期限」,這串全是本機輸入、沒一步去問 S3;且 AWS 對比指出另一種發臨時憑證的做法「每產一組憑證都要打一次 API(=連到遠端服務跑一趟、要等它回話)」,presigned 則不必為此打 API。
- 驗證時 S3 用網址參數重算一次簽章比對、檢查是否過期、憑證此刻是否仍有效有權限——全過才給檔。
- (誠實補:AWS 對 S3「零連線」沒有逐字白紙黑字,此點以官方輸入清單+臨時憑證對比+Cloudflare R2 明文為據。)
-
綜合題:同事問你「這條網址憑什麼能下載私有檔、卻不用登入」,請用一段話完整回答(要點到簽章、bearer token、權限天花板)。看答案收合
「這條網址不用登入,是因為身分已經被算成一段簽章跟著網址走了(網址帶的是帳號的公開識別碼,不是密碼);它是 bearer token,誰拿到誰能在期限內用;而且它能做的,絕不超過簽它的人本來的權限。」
- 它=一個先簽好名的 HTTP 請求,帶著一段簽章與一個有效期限,整包壓進網址。
- 它解決的問題:讓沒帳號的人限時存取私有檔,而你不用公開檔案/不用改權限設定/不用交出密碼。
- 能講出這段,這一站就過關了。
一句話定義:它是「一個先簽好名、整包壓進網址裡的 HTTP 請求」
先給最精準的一句話,這句直接來自 AWS 官方:
pre-signed URL 是「一個被 IAM 認得的 HTTP 請求」。 它跟一般 AWS 請求的差別,在於它多帶了一個「有效期限」;而且跟其他需要驗證的請求一樣,它也帶著一段用你的憑證算出來的簽章。
(IAM=AWS Identity and Access Management,是 AWS 的身分/權限管理系統,可以想成 AWS 的「門禁系統」——誰是誰、能做什麼,都它在管。這是本文第一次、也幾乎是唯一需要記住的專有名詞。)
這句話拆開來看,關鍵是三個詞:HTTP 請求、期限、簽章。
- 平常你的程式打 S3,是一個帶著身分憑證的 HTTP 請求(「我要下載這個物件」)。
- pre-signed URL 做的事,是把「這個請求本來該長的樣子」——做什麼動作、對哪個物件、什麼時候發、多久內有效——全部塞進一條網址的 query string(
? 後面那串),再附上一段用你的憑證算出來的簽章。
- 於是,這條網址本身就「等於」一個完整、已經簽好名、可以直接送出的請求。誰把它送出去都行。
比喻:它像一張「已經簽名蓋章的取件單」。 你不需要本人到場、不需要出示證件;單子上寫死了「憑此單、在 X 月 X 日前、可領走 3 號櫃第 5 格的東西」,還蓋了只有你能蓋的防偽章。櫃檯驗章沒問題、也還沒過期,就把東西給拿單子的人。單子本身就是通行證,不是你的身分。
這就回答了開頭的魔法:那條網址不需要「登入」,因為它自己就是一個簽好名的請求。身分證明已經被壓縮成那段簽章,跟著網址一起走了。
先打一劑預防針,免得你之後拆解網址時看到裡面的內容嚇一跳:嚴格說,網址裡其實帶了你帳號的公開識別碼(等於帳號那半,本來就不是秘密)。但它沒有帶密碼——真正的秘密(那把 secret key)從頭到尾沒出現在網址裡,它的效力早被壓縮成那段簽章。所以「不用登入、不用把密碼給對方」這個鉤子成立;只是別誤會成「網址裡什麼身分資訊都沒有」。
它解決什麼問題:讓沒帳號的人也能限時存取私有檔,而你什麼都不用交出去
沒有 pre-signed URL 的話,要讓外人存取一個私有物件,你的選項都很痛:
- 把物件或 bucket 設成公開 → 那就人人可看,失去私有的意義,而且很難收回。
- 改 bucket 的權限設定開一個洞 → 動到整個 bucket 的存取規則,容易改錯、也難針對「某一個檔、某一個人、某一段時間」。
- 把密碼給對方 → 等於把家裡鑰匙複製給人,對方能做的遠不只下載這一個檔。
pre-signed URL 把這三個痛點一次解掉。AWS 官方對它的定位是:
你可以用 pre-signed URL 在不更新 bucket 權限設定的前提下,授予對某個物件「限時」的存取權。上傳方向也一樣——它讓別人可以上傳一個指定物件,而不需要對方擁有任何 AWS 帳密或權限。
翻成白話,它同時做到三件別的方法做不到的事:
- 對方零憑證:拿到 URL 的人不需要有你們雲端的任何帳號、密碼、權限。
- 限時:URL 帶著期限,過期自動失效,不用你事後回去手動收回。
- 範圍極小:這條 URL 就只能做「當初簽的那一件事」(下載這一個 key),不會擴散到別的檔、別的操作。
而你這邊,不用公開物件、不用改 bucket 權限設定、不用外洩密碼。三個痛點全避開了。
它本質是 bearer token:誰拿到、誰就有效,所以要當秘密保護
這是整站最重要的一個觀念,請一定記住。AWS 官方原話:
pre-signed URL 本質上就是 bearer token,會把存取權授予「持有它的任何人」。因此我們建議你妥善保護它。
「bearer token」直譯是「持有者令牌」——持有即有效。它不認人,只認「你手上有沒有這張令牌」。
比喻:它像一張不記名的演唱會門票。 票上不印你的名字,驗票員只看你手上有沒有這張票。你把票掉了、被撿走了、拍照發到群組被人存下來了——撿到/存到的人都能直接進場,門口不會問「你是不是本人」。
這個性質帶出一個你必須內化的結論:pre-signed URL 是秘密,要當密碼一樣保護。
- 它一旦外洩,在到期前,任何撿到的人都能做那條 URL 允許的動作(下載那個私有檔/上傳到那個 key)。
- 所以它不該被隨手貼進聊天室公開頻道、不該寫進 log、不該出現在任何會被無關的人看到的地方。
- 這也是為什麼「期限要短」很重要——令牌活得越短,撿到也越快作廢。(期限怎麼設是 Level 5 的細節,這裡先知道「因為它是 bearer token,所以短命是好事」就夠了。)
權限天花板 = 產生者的權限:URL 能做的,絕不超過簽它那組憑證被允許的範圍
很多人第一次接觸會擔心:「這條網址這麼萬能,會不會被拿去存取別的東西、搞破壞?」不會。因為它有一道硬天花板。AWS 官方原話:
pre-signed URL 的能力,受限於「產生它的那個 user 的權限」。
AWS 的最佳實務指南講得更死:
一條先簽好的請求只能允許「簽它的那組憑證本來就被允許的動作」。如果那組憑證(不管是明示或隱含地)禁止了該動作,這個請求送出去時就會被拒絕。
白話說:簽名的人有多大權限,這條 URL 頂多就那麼大,不會多一分。
- 你只有
s3:GetObject(這是 S3「讀取物件」權限的正式名稱)權限,就算你手滑簽了一條 PUT(上傳)URL,對方拿去用一樣會被擋。
- 你根本沒有某個 bucket 的權限,你為它簽的 URL 也是廢的——一用就 403。
- 這條 URL 無法被拿去存取「簽它的憑證本來就碰不到」的其它資源。它不是一把萬能鑰匙,它是「你自己那把鑰匙能開的門」的一個限時副本。
關鍵直覺:pre-signed URL 不會「放大」權限,只會「轉授並限縮」你已有的權限。 它把你的權限切出一小片(單一物件、單一動作、限定時間),包成一條網址交出去。切出來的片,絕不可能比原本那塊大。
誰能「產」vs 誰能「用得成」:兩件不同的事
這兩件事常被混在一起,分清楚就通了。AWS 官方原話:
任何有有效憑證的人都能產生一條 pre-signed URL。 但要讓別人能「成功存取」那個物件,這條 URL 必須是由「真的有權限執行該操作的人」簽出來的。
拆成兩層:
- 誰能「產」:門檻很低——只要你手上有一組有效的憑證,你就能簽出一條語法正確的 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「零連線」的白紙黑字,我在這次爬過的頁面裡沒找到逐字版本,故此點以上述幾項為據。)
收尾:一口氣把六件事串起來
如果同事問你「這條網址憑什麼?」,你現在應該能一口氣講完——講得出下面這六點,這一站就過關了:
- 它是一個先簽好名的 HTTP 請求,帶著一段簽章與一個有效期限,整包壓進網址;網址裡帶的是帳號的公開識別碼,不是密碼。
- 它讓沒帳號沒權限的人也能限時存取私有物件,而你不用公開檔案、不用改 bucket 權限設定、不用交出密碼。
- 它是 bearer token——持有即有效,所以要當秘密保護。
- 它的權限天花板就是簽它那組憑證的權限,不會多一分。
- 有效憑證就能「簽」,但要「用得成」得簽的人真的有那個權限——能簽不等於簽了有用。
- 簽是純本機運算、不連 S3;驗證才在物件被存取時由 S3 執行。
下一站(Level 2)我們再分「下載該用 GET、上傳該用 PUT」,以及瀏覽器怎麼直接把檔案傳上 S3。
參考來源(實際爬過的權威連結)
- AWS Prescriptive Guidance — Overview of presigned URLs(定義「被 IAM 認得的 HTTP 請求」、「先簽好的請求只能允許簽它的憑證被允許的動作」、與臨時憑證做法的對比:不需打 API)
- Amazon S3 User Guide — Download and upload objects with presigned URLs(「在不更新 bucket 權限設定下授予限時存取」、「不需對方擁有 AWS 帳密」、「presigned URLs 本質是 bearer tokens」、「能力受限於產生它的 user 的權限」、「任何有有效憑證的人都能產生」、「建立時要提供憑證並指定 bucket/key/動作/期限」、403 常見問題)
- Cloudflare R2 — Presigned URLs(「Presigned URLs are an S3 concept」、產生時「完全不與 R2 通訊」、僅需 API 憑證 + 簽章演算法實作)