I am building a simple CRUD app (not using the CRUD module).
My model is a simple class with one attribute. the id is implicitly inheritied from Model.
@Entity
public class Account extends Model {
@Required
public String domain;
}
The view is as follows. Please note the hidden field with 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>
I have been able to build a scenario where save,update works.
The way update is done is I read the ID from hidden field, and update the record. If ID is not available, a new record is created.
So the question is: Can the ID be hacked i.e modified so that I change 1 to 2, and assuming a record with 2 exists, it gets overwritten. (I suppose it shouldn't be difficult with firebug or other plugins).
How do I prevent this? One option I thought of is to read the record with the given Id, if user is allowed to modify it, I allow update, otherwise not. This is still not fool proof because, while the user could be allowed, "wrong" record could be modified.
I imagine this is a known problem and hopefully with a known solution.
Thanks for taking the time to answer my question.
So the question is: Can the ID be hacked i.e modified so that I change 1 to 2, and assuming a record with 2 exists, it gets overwritten. (I suppose it shouldn't be difficult with firebug or other plugins).
How do I prevent this? One option I thought of is to read the record with the given Id, if user is allowed to modify it, I allow update, otherwise not. This is still not fool proof because, while the user could be allowed, "wrong" record could be modified.
Of course, it is possible for an attacker to change the id of the record.
there are several ways to minimize the impact of this attack.
1) easiest way - Object fetching:
Fetch the Object from the database and check if it belongs to the user in question. This will prevent other users from messing around with objects that don't belong to them, but will not prevent a user to change another object belonging to him. This is an easy way and sufficient in most cases.
2) more complicated: signing:
The idea here is to sign the constants you provide to the template and check if the hash still matches after form submission. This is very similar to what play does with its session. Its impossible for an attacker to mess around with the constants (e.g. id) and provides the most security.. however, you'll have more work to do.
Example:
public static void someActionDisplayingForm(){
SomeObject o = ....
SomeOtherObject o2 = ....
String constants = o.id + "|" + o2.id;
String hash = Crypto.sign(constants);
render(o, o2, hash);
}
in the template you have
#{form ...}
<input type='hidden' name='id1' value='${o.id}' />
<input type='hidden' name='id2' value='${o2.id}' />
<input type='hidden' name='hash' value='${hash}' />
in the method processing the form you'll do
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();
...
}
Hope that helps.
Can the ID be hacked i.e modified so that I change 1 to 2, and assuming a record with 2 exists, it gets overwritten. (I suppose it shouldn't be difficult with firebug or other plugins).
You are correct. Editing such things can be as easy as inspecting and editing the element in Chrome's console. Remember; anything that is done client-side is insecure and can be modified by the user. Always have server-side checks, always.
How do I prevent this?
One possible fix is to link records to users, i.e., create a bridging table between users and records called "recordAccess" (or whatever your naming convention leads you to call it). This bridging table will have a user ID column and a record ID column. The server will check the user ID and the record ID against this table and will only allow changes if there is a matching row in the database. How you add rows to this table depends on how your app works, but shouldn't be difficult to work out.
To prevent users from editing the wrong record, you could add an additional column into this bridging table called "current" (or, again, whatever you prefer) which is a simple boolean value. When the user goes to edit a record that he/she is allowed to edit, this value will be set to "true" and all other rows associated with that user will be set to "false". Then, when the user submits the edit, if the value in that row is set to "true", the row successfully updates and the value changes back to "false". Otherwise, all values are set to "false" and the update is rejected.
Hopefully this gives you some ideas.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With