2012-06-01 74 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