ArOZ Online Pre-1.0 檔案存取路徑虛擬層
Toby
Toby
ArOZ Online BETA 與 Pre 1.0 版本的差別

在 ArOZ Online Pre-1.0 裡面,我幫 ArOZ Online 系統加上了一層虛擬層;你可能會問:為甚麼要加這個東西?這真是一個好問題,如果不是我開發過一個這樣的系統我也不知道檔案路徑虛擬化的重要性

問題一:檔案路徑安全性

一般如果你用 PHP 來寫系統,你很容易會使用一個檔案的真實路徑。舉個例子,你想讓用家選擇一個檔案,然後打開讓用家下載那個檔案,一般來說你會使用 realpath() 這個功能。然而,這有一定的危險性,例如有人在傳給伺服器的資料中加入 “../” ,讓他能離開你指定的存取範圍。

在 ArOZ Online Beta 的 implementation 中,由於所有檔案都是使用真實路徑存取的,這導致使用者很容易就可以在 path 裡面偷塞一點奇怪的字符以存取一些本來不應該被存取的東西。
當然,你可以加一點東西來避免這問題,好像 Stack Overflow 上就有這樣的答案

Stack Overflow 上避免 PHP Directory Traversal 的方法

然而,每次都要透過一個特定的 function 來處理,總會有一天出問題的。(好像說某個開發者忘了用這個 function 或是這個 function 本身有 bug)

問題二:外置存取裝置

由於 ArOZ Online Beta 系統由原本的小網頁變成了一個類似作業系統的物體,它也需要去管理外置的存取裝置(如外接硬碟,或是 www root 所 mount 在的硬碟)。然而 PHP 並不是設計來做這樣的跨硬碟存取的,所以自然有不少的 Bug 存在,而開發起需要存取外置裝置的時候也特別麻煩,需要為。

在 ArOZ Online Beta 的 implementation 裡,使用者需要在 Apache conf 裡面設定 modXSendFile 來讓 PHP 可以在外置硬碟提供(serve)大型檔案如影片,音樂等等。然而,由於外置存取位置的路徑被直接寫進了 Apache conf,即使使用者想更改存取路徑也沒有辦法簡單完成。

解決方案:檔案路徑虛擬化

甚麼是路徑虛擬化?簡單來說就是把 file 的存取路徑進行轉換,讓不同的裝置也能夠輕易的讓模組使用 Virutalized path 來存取。簡單來說是這樣:

  1. 請求 Virtual Path
  2. 模組把 Virtual Path 掉到 file system 的轉換 function
  3. 回傳真實路徑
  4. 處理資料

以 ArOZ Online Pre-1.0 的 File system listdir 功能來說,先假設你有兩隻 HDD mount 在了 /media/storage1 跟 /media/storage2,並把 storage.json 設定成以下的樣子:

[
  {
    "name":"Storage 1",
    "uuid":"S1",
    "path":"/media/storage1",
    "access":"everyone",
    "hierarchy":"users",
    "automount":true
  },
  {
    "name":"Storage 2",
    "uuid":"S2",
    "path":"/media/storage2",
    "access":"everyone",
    "hierarchy":"public",
    "automount":true
  }
]

然後你可以傳入以下虛擬路徑用來處理檔案

S1:/video/
S2:/
user:/Music
user:/Desktop/test

然而實際上,上術的虛擬路徑卻是在存取以下的真實路徑

/media/storage1/users/{username}/video
/media/storage2/
./files/users/{username}/Music
./files/users/{username}/Desktop/test/

而設定當中,hierarchy 就是決定了虛擬路徑構造的元素,裡面的原理有點複雜,但是作為開發者,你只要存取 virtualPathToRealPath() 這個功能就能夠取得真實路徑了,簡單吧?