【Laravel實戰】15分鐘搞懂Livewire的安全機制
對於 Livewire 新手來說,這種體驗有些神奇。感覺好像頁面加載時,你的 Livewire 組件位於伺服器上,偵聽來自瀏覽器的更新並實時對其進行響應
這與 Phoenix LiveView 等其他類似工具的工作方式相距不遠
無論 Livewire 感覺如何的相似,它的內部工作方式都有很大不同,各有利弊
Livewire 組件感覺像是有狀態的,但其實完全是無狀態的。伺服器上沒有長時間運行的 Livewire 實例等待瀏覽器進行交互,因此每次交互都是全新的請求與響應
為了更全面地掌握這種概念,讓我們以下面的簡單"計數器"組件來了解
//app/Http/Livewire/Counter.php
class Counter extends Component
{
public $count = 1;
public function increment()
{
$this->count++;
}
public function render()
{
return view('livewire.counter');
}
}
//resources/views/livewire/counter.php
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
</div>
從使用者的角度來看,使用“計數器”的使用者體驗是這樣的:用戶加載頁面,看到數字1,點擊"+"按鈕,現在看到數字2
以下是 Livewire 如何實際工作以實現此效果的流程圖

總而言之,當使用者訪問包含計數器組件的頁面時,一個通常的請求會像其他頁面一樣發送到伺服器。該頁面會像任何普通的 Blade 組件一樣呈現計數器的初始視圖,但是除了呈現HTML之外,Livewire還會“dehydrates”或“序列化”組件的狀態(公共屬性)並將其傳遞到前端
現在前端具有組件的狀態,當觸發更新(比如按下“+”按鈕)時,會將請求發送到服務器,包括最近已知的組件狀態。服務器從該狀態“hydrates”或“反序列化”組件並執行任何更新
現在,該組件再次 “dehydrated” 以向瀏覽器提供新呈現的HTML和更新的狀態,以供以後的交互請求使用,以下這是請求期間實際組件生命週期的流程圖

希望你現在已經更準確的了解關於 Livewire 幕後的工作方式與流程。這將使你能夠更好的找出問題,並了解使用 Livewire 的性能和安全隱患
安全檢測
記得剛才有提過每個 Livewire 請求都是“無狀態的”,即沒有長時間運行的服務器實例來紀錄狀態。狀態儲存在瀏覽器中,並在請求之間來回傳遞給服務器
由於狀態儲存在瀏覽器中,因此很容易受到前端操縱的影響。如果沒有適當的安全措施,歹徒在兩次請求之間去操縱瀏覽器中組件的狀態並不困難
在我們的計數器例子中,操作與該組件的計數一樣瑣碎和短暫的操作並沒有真正的負面影響,但是在具有更大風險的組件中,例如帶有刪除按鈕的“編輯文章”組件,就需要採取安全措施
校驗
Livewire 用以確保安全的基礎機制為 "checksum",會伴隨所有的請求/回應來使用。目的是驗證瀏覽器中伺服器的狀態是否未被篡改
這樣說比較好理解,比如剛才所說過的計數器組件。 Livewire 不會簡單地將 {count:1} 傳遞給瀏覽器,而是會使用安全密鑰生成 Hash 碼用於安全驗證並將其與狀態一起傳遞
計數器 的Livewire 組件,其狀態真實內容如下所示:
{
state: { count: 1 },
checksum: "A6jHn359Ku3lFc82arW8",
}
現在,如果歹徒在兩次請求之間篡改了瀏覽器中的狀態,則在 Livewire 處理組件更新之前,它將發現安全驗證的 Hash 碼不正確因而引發錯誤
持久中介層
Livewire採取的第二項安全措施是“持久中介層”,這意味著 Livewire 將捕獲在“初始請求”期間使用的任何身份驗證/授權中介層,並將其重新應用於後續請求
如果沒有此措施,則在使用者從應用登出後, Livewire 後續請求可能會被捕獲並重播,但不再有權訪問這些程式碼路徑
預設情況下,Livewire 重新應用每個 Laravel 應用附帶的現成的身份驗證和授權中介層。這是幾個預設值:
[
...
\Illuminate\Auth\Middleware\Authenticate::class,
\Illuminate\Auth\Middleware\Authorize::class,
]
如果你希望添加自己的中介層以進行捕獲並重新應用(如果存在),則可以在應用的服務中添加以下API:
Livewire::addPersistentMiddleware([
YourOwnMiddleware::class,
]);
現在,如果將中介層分配給加載組件的原始路由,則你添加的所有中介層都將重新應用於後續的 Livewire 請求



