最近因為 Cloudfront 的流量費用越來越可怕了,
所以牙一咬就決定擋掉圖片的所有外連圖個減少開銷。
而 Cloudfront 正好有提供 Signed URL 這個玩意可以達成我的要求。
這玩意簡單來說就是在所要求的資源(如:圖片、檔案等)的網址後面多加一串 Query String。
例如:http://www.example.com/a.txt
經過改造後會變成http://www.example.com/a.txt?blahblah
,
而Server只要認那串 Query String 就可以決定是否要出所要求的內容,
就可以控制不必要的外連。
那接著就不提廢話,直接實作吧!
第一步要先到 AWS 的 Security Credentials ,
然後頁面往下拉找到一個 Key Pairs 的 tab,
接著點擊 Create a new key pair ,
他會產生一組pem檔並且要求下載,
請把這個檔案下載儲存。
同時頁面上也會顯示一組 Axxxxxxxxxx 的 key ,
請務必把這組字串複製下來。
第二步要寫出一個產生 Signed URL 的 function,
內容大概如下
<?php
/**
* $resource:要處理的檔案網址 例如http://www.example.com/a.txt
* $expire:過期的時間,單位是秒,這裡我預設有效時間為一個小時
*/
function create_signed_url ($resource, $expire = 3600)
{
$aws_key = 'Axxxxxxxx'; // 就是上述所提到的key
$pem_file = ''; // 剛才下載的pem檔案放置路徑
$expire_time = time() + $expire; // 這裡的值是個 Unix timestamp
// 以下是 Cloudfront 的存取策略,內容基本上是個json string
// 但是千萬不要用json_encode這個函式去編出內容,因為格式會不一樣
// 詳細可以參考:
// 以下是指特定的檔案(即$resource)在$expire_time之後即無法取得內容
$policy = '{
"Statement":[{
"Resource":"' . $resource . '",
"Condition":{
"DateLessThan":{
"AWS:EpochTime":'. $expire_time . '
}
}
}]
}';
// 接下來要利用openssl的相關函式產生所需的簽章內容
$private_key_content = file_get_contents($pem_file);
// 先把內容丟到openssl_get_privatekey算出私鑰
$pkey = openssl_get_privatekey($private_key_content);
// 接著呼叫openssl_sign取得簽章內容
// $policy是上面設定的讀取策略,產生的結果會放在$signature中
openssl_sign($policy, $signature, $pkey);
// 接著釋放這組key內容
openssl_free_key($pkey);
// 然後要真正產生簽章過的URL
// 請注意:Policy和Signature的內容要用base64_enocde編碼外,還要把特定的三個符號替換掉 // 否則產生的url也會無法取得資源
return $resource."?".http_build_query(array(
'Policy' => str_replace(
array('+', '=', '/'),
array('-', '_', '~'),
base64_encode($policy)
),
'Key-Pair-Id' => $aws_key,
'Signature' => str_replace(
array('+', '=', '/'),
array('-', '_', '~'),
base64_encode($signature)
),
));
}
?>
然後在網頁上用到該資源的連結/圖片全部用這個function處理後,
輸出的url應該就會有一長串的Query String了。
但是這樣作還不夠,
我們還要進去 Cloudfront 的控制台設定哪些項目需要被限制存取。
所以進入控制台後請選擇目標項目後點擊 Distribution Settings
接著選擇 Behaviors,
如果沒意外的話有一組 Path Pattern 為 Default(*) 的項目,
請點擊他後按下Edit。
出現編輯畫面後請往下拉,
找到 Restrict Viewer Access (Use Signed URLs) 並選擇 Yes 後儲存。
這樣這個項目內所有資源就會被限制存取。
(當然也可以設定什麼樣的檔案才要被限制,這個設定可以寫在 Path Pattern 中)
上面的動作做完後,等 Cloudfront 佈署完成後應該就會生效了。
你應該會發現沒加一長串簽章的網址全部都出現 Access Denied 或是其他之類的錯誤訊息,
而有一長串簽章的網址都應該是可以正確讀取,
這樣表示就一切正常了。
留言