2012-06-01 87 views
7

我正在構建一個簡單的CRUD應用程序(不使用CRUD模塊)。如何防止帶有ID的隱藏字段被黑客攻擊

我的模型是一個具有一個屬性的簡單類。 id是從Model中隱式繼承的。

@Entity 
public class Account extends Model { 

    @Required 
    public String domain; 
} 

該視圖如下。請注意帶ID的隱藏字段。

<form class="form-horizontal" action="@{Application.save}" method="POST"> 
<fieldset> 
    <legend>Settings</legend> 
    <input type="hidden" name="account.id" value="${account?.id}"> 

    #{field 'account.domain'} 
    <div class="control-group #{if field.error != null} error #{/if}"> 
     <label class="control-label" for="${field.id}">&{field.name}</label> 
     <div class="controls"> 
      <input type="text" class="input-xlarge" id="${field.id}" value="${field.value}" name="${field.name}"> 
      <span class="help-inline">${field.error}</span> 
     </div>   
    </div> 
    #{/field}   

    <div class="form-actions"> 
     <input class="btn btn-primary" type="submit" value="Save"> 
    </div> 

</fieldset> 

我已經能夠建立這樣一個場景,保存,更新工作。

的方式更新做的是,我讀了隱藏字段的ID,並更新記錄。如果ID不可用,則創建新記錄。

所以問題是: ID可以被破解,即修改,使我改變1到2,並假設與2存在的記錄,它會被覆蓋。 (我猜想用螢火蟲或其他插件應該不難)。

我該如何預防?我想到的一個選擇是用給定的Id讀取記錄,如果允許用戶修改它,則允許更新,否則不允許。這仍然不是傻瓜證明,因爲雖然用戶可以被允許,但「錯誤的」記錄可以被修改。

我想這是一個已知的問題,並希望與已知的解決方案。

感謝您花時間回答我的問題。

回答

9

所以問題是:ID可以被破解,即修改,以便我更改 1到2,並假設存在2的記錄,它會被覆蓋。 (I 假設用螢火蟲或其他插件不應該很困難)。

我該如何預防?我想到的一個選擇是使用給定的Id讀取記錄 ,如果允許用戶修改它,則允許更新,否則不允許更新, 。這仍然不是萬無一失的,因爲雖然可以允許用戶 ,但可以修改「錯誤」記錄。

當然,攻擊者可能會更改記錄的ID。

有幾種方法可以最大限度地減少此攻擊的影響。

1)最簡單的方法 - 對象獲取

從數據庫讀取的對象,並檢查其是否屬於有問題的用戶。這將防止其他用戶混淆不屬於它們的對象,但不會阻止用戶更改屬於他的另一個對象。在大多數情況下,這是一種簡單的方法。

2)更加複雜:簽約

這裏的想法是標誌你提供的模板,並檢查哈希表單提交後仍然匹配的常量。 這與遊戲會話的作用非常相似。攻擊者不可能混淆常量(例如id)並提供最大的安全性。但是,您需要做更多工作。

例子:

public static void someActionDisplayingForm(){ 
    SomeObject o = .... 
    SomeOtherObject o2 = .... 
     String constants = o.id + "|" + o2.id; 
     String hash = Crypto.sign(constants); 
     render(o, o2, hash); 
} 
模板

你有

#{form ...} 
    <input type='hidden' name='id1' value='${o.id}' /> 
    <input type='hidden' name='id2' value='${o2.id}' /> 
    <input type='hidden' name='hash' value='${hash}' /> 

的方法處理表單,你會做

public static void processing(String id1, String id2, String hash, String otherValues, ...){ 
    String constants = id1 + "|" + id2; 
    String checkHash = Crypto.sign(constants); 
    if(!checkHash.equals(hash)) 
    badRequest(); 
    ... 
} 

希望有所幫助。

+0

這看起來正是我所需要的。 Crypto.sign計算HMAC.SHA1簽名。今晚我會嘗試一下。我一直在研究的是具有用戶特定的祕密,但這是一個實現細節。你已經澄清了我心中的陰霾。謝謝:) – Nasir

+0

就像一個魅力。比維護服務器狀態更簡單。我打算使用用戶特定的密鑰,我將在註冊時生成密鑰,而不是默認使用的應用程序密鑰。 [帶2個參數的符號方法](http://www.playframework.org/documentation/api/1.2/play/libs/Crypto.html#sign%28java.lang.String,%20byte []%29) – Nasir

+0

I'米不知道爲什麼你會打擾。 Play框架是完全無狀態的。如果它可以發現只有帳號ID 1可以在GET上修改,爲什麼它不能在POST上算出來呢?會話已經識別用戶。沒有理由加密其他任何東西。 –

1

是的,它可以修改。這不需要真正的知識或技能。在任何情況下,除非您驗證了其他信息,否則不得信任來自用戶的信息。

爲了做到這一點,你需要某種形式的服務器端邏輯的。在很多情況下,這只是服務器上與用戶對象鏈接的一個會話,允許您執行授權(您可以確保該記錄是可以修改的記錄;哪一個更重要,並且是故意用戶引起的錯誤,而不是安全風險)。

只要你可以配合請求回用戶,然後確保用戶被允許執行請求,你是好。最簡單的方法是典型的會議,但有很多空間。

2

能否ID被黑客攻擊即修改,使得我改變1〜2,和 假設記錄有2存在,它就會被改寫。 (我想這對 不應該是困難的螢火蟲或其他插件)。

你是正確的。編輯這些內容可以像在Chrome控制檯中檢查和編輯元素一樣簡單。記得;客戶端完成的任何事情都是不安全的,並且可以由用戶修改。始終有服務器端檢查,總是

我該如何預防?

的一種可能的解決方法是記錄鏈接到用戶,即,在用戶和記錄之間創建一個名爲「recordAccess」的橋接表(或任何你的命名約定引導你稱之爲)。該橋接表將具有用戶標識列和記錄標識列。服務器將根據此表檢查用戶標識和記錄標識,並且只允許在數據庫中存在匹配的行時進行更改。如何將行添加到此表取決於您的應用程序的工作方式,但不應該很難解決。

爲了防止用戶編輯錯誤的記錄,您可以在此橋接表中添加一個名爲「current」(或者,再次,無論您更喜歡)的附加列,這是一個簡單的布爾值。當用戶編輯允許編輯的記錄時,該值將設置爲「true」,並且與該用戶關聯的所有其他行都將設置爲「false」。然後,當用戶提交編輯時,如果該行中的值設置爲「true」,則該行成功更新並且該值將變回「false」。否則,所有值都設置爲「false」並且更新被拒絕。

希望這給你一些想法。

+0

謝謝。現在,我正在探索這種與某種消息摘要的結合。 HMAC(rfc 2104)似乎符合該法案。我需要更好地理解它。如果我有任何進展,請更新此主題。 – Nasir