2017-07-25 43 views
2

雖然看着this answer的問題Why do we use ViewModels?,我碰到這一節就來了:ViewModels如何防止惡意數據庫更改?

「視圖不應包含任何非表象的邏輯」和「你 不應該相信的視圖」(因爲視圖可以由用戶提供)。通過 提供一個Model對象(可能仍然連接到一個活動的 DatabaseContext),一個視圖可能會惡意更改您的數據庫。

這究竟是指什麼?如果我的Model和我的ViewModel中有UserIdPassword,那麼安全性是從哪裏來的?在控制器中進行某種檢查?我們檢查什麼?

我們如何確定我們可以信任視圖中的數據?這是由防僞令牌處理的嗎?

+0

當您使用視圖模型,你推到DB如果您使用的仍然是連接到活動databasecontext的觀點能夠在某些情況下,仍然可以通過壞數據進入DB這不會是一個模型,然後才能驗證數據可以用真實視圖模型。 –

+0

@Derek問題不在於不恰當地管理連接而不是使用ViewModel,然後呢? – Sinjai

+0

問題是模型聯編程序會盲目地更新模型中的值。如果模型連接到實體框架中的某個實體,它最終可能會更新您不想要的字段。一個適當的視圖模型將完全脫離這樣的事情。 –

回答

3

我相信答案指的是過問題。當您直接在視圖中使用實體類時,特別是如果將該發佈的實體直接保存到數據庫中時,惡意用戶可以修改該表單以發佈他們不應該修改的字段。

例如,假設您的表單允許用戶編輯小部件。我們還要說,你有行級權限,這樣用戶只能編輯屬於他們的小部件。所以,我們的虛構的惡意用戶Joe編輯了一個他可以使用id 123編輯的小部件。但是,他決定他想要與Jane的小部件混在一起,所以他在名爲Id的表單中添加了一個字段,併爲其賦予了Jane的小部件ID。當喬然後發佈窗體小部件時,Jane的窗口小部件將被更新。

視圖模型並不僅僅是爲了解決這個問題,但它基本上否定了這個問題,因爲從本質上講,您不能直接將視圖模型保存到數據庫中。相反,在將實體保存到數據庫之前,必須將視圖模型的值映射到實體上。因此,你明確地控制了什麼和沒有被映射,所以在上面的例子中,Joe改變id最終沒有效果,因爲你沒有將它映射到實體上。

實際上,real這裏的問題是直接將用戶發佈的任何內容直接保存到數據庫中。您實際上仍然可以將實體類作爲「模型」提供給視圖,但不保存發佈的實例。相反,您可以創建實體的新實例或從數據庫中提取新實例,並簡單地將已發佈實例的值映射到該實例。再一次,你不會映射像Id這樣的屬性,所以Joe又被挫敗了。換句話說,解決問題的不是視圖模型,而是永遠不會相信用戶足以直接保存通過POST創建的任何內容,從而解決問題。

Microsoft以Bind屬性的形式給出了另一種替代解決方案,它基本上允許您在模型綁定過程中包含/排除實體類的某些屬性(換句話說,忽略任何發佈的值)。因此,例如,您可以通過在[Bind(Exclude = "Id")]上對您的操作參數進行裝飾來解決上述問題,然後丟棄Id的任何已發佈值。但是,Bind對於number of reasons來說太可怕了,您不應該真正使用它。始終使用視圖模型,或者直接不要直接保存由模型綁定器創建的實體實例。

+0

非常有用的文章不完全相關,但絕對不保證其自身的問題:你如何改變什麼被髮布到控制器?我生成的編輯(更新)方法只需要一個'int?'。我甚至不確定它是從哪裏來的,除了視圖中的'Html.HiddenFor(model => model.Id)'外。有太多的抽象...... – Sinjai

+0

它*應該*來自路線(即URL)。編輯路由通常是'/ foo/edit/{id}',其中'{id}'是您要編輯的「foo」的主鍵。您*可以*將其作爲隱藏的信息發佈,但同樣,您可能會面臨潛在的安全問題。該URL唯一標識一個特定的資源(因此名稱),所以更改id字面意思是你要求一個完全不同的資源。然後您可以使用標準的行級權限處理任何嘗試的URL操作。 –

+0

生成了'HiddenFor'。坦率地說,我害怕刪除它,因爲我對整個架構的理解充其量是脆弱的。我仍然試圖找出這個第一個參數來自'Update(FooViewModel model,int id)'的地方。視圖總是將他們的模型傳遞給視圖,或者是什麼?順便說一句,你在守護者身上很棒... – Sinjai