views:

234

answers:

7

I have an POJO in Google Web Toolkit like this that I can retrieve from the server.

class Person implements Serializable {
  String name;
  Date creationDate;
}

When the client makes changes, I save it back to the server using the GWT RemoteServiceServlet like this:

rpcService.saveObject(myPerson,...)

The problem is that the user shouldn't be able to change the creationDate. Since the RPC method is really just a HTTP POST to the server, it would be possible to modify the creationDate by changing the POST request.

A simple solution would be to create a series of RPC functions like changeName(String newName), etc., but with a class with many fields would require many methods for each field, and would be inefficient to change many fields at once.

I like the simplicity of having a single POJO that I can use on both the server and GWT client, but need a way to do it securely. Any ideas?

EDIT

I'm resubmitting with a bounty to try and see if there are any other ideas. Perhaps my original question focused too much on the specifics of GWT. Really I think this is a generic question for any system that uses JavaBeans to pass data between a secure (servlet container) and insecure (web browser) environment.

EDIT 2

Also, to be clear, I used the field creationDate as an example of the problem. In reality the code I'm working with is more complicated with many different fields.

A: 

Well...an academical (i.e. theoretically possible, but quite impractical) solution might be to hash the object's state using a throw-away public key who's private key is on the server. It might go something like this:

  1. the server generates public-private key pair
  2. the server sends the public key along with the real data to the client
  3. the client calculates a hash of the full object's state together with the public key
  4. the client sends the object and the hash to the server
  5. the server recalculates the hash to confirm the integrity of the package

Assuming the key-pair is changed at each requset and that the user can't interfere with the hashing process (which he can, but might be difficult enough to make it useful in some use cases), the server would be able to detect any change in the objects state done after the hash has been calculated on the client.

Again, consider this nothing more than a thought experiment...I wouldn't suggest you implement such an approach. In general, you have to be able to guarantee the logic on the client hasn't been tampered with before you get to securing the data.

Tomislav Nakic-Alfirevic
Why would someone add cryptography complexity only to avoid database updates in pre-determined columns?
jweyrich
As I said, it's not something I'd recommend doing. I understood the question to basically be "how should one prevent the user from changing a part of a value (in the given technological environment)". An obvious solution to me is to sign the data to guarantee it hasn't been tampered with. Maybe we understood the question in different ways.
Tomislav Nakic-Alfirevic
You understand the problem as "How to avoid traffic manipulation". If it were the case, he could simply use HTTPS.
jweyrich
Not really: HTTPS would protect the message once it leaves the client until it arrives to the server. What I thought gerdemb wants is to prevent the user to modify the POST request before it's sent to the server. But, we're exchanging an awful lot of comments on a moot subject...
Tomislav Nakic-Alfirevic
Still not necessary if this data (creationDate) is simply ignored by the server. Agreed, I stop here.
jweyrich
+2  A: 

If the client shouldn't be able to change the creationDate and have it stick, change your serialization (e.g. your SQL UPDATE statement) to not save that specific field. It should only be set from an INSERT (where it will come from either the RPC endpoint server, or your database server if you set an automatic default).

Mark Peters
Exactly. "Never trust the client". If you have information that the user shouldn't be able to change, don't trust the data coming from the client. If you're not saving the data to persistent storage until after the user has a chance to modify it, serialize it beforehand and keep a temporary copy to pull the data that's not supposed to have been modified.
Brian Roach
+2  A: 

I recommend you to keep your single RPC method, and use a POJO/bean mapper like Dozer or Gilead.

  • With Dozer, you create a class-mapping that is used to copy properties from one object to another. If you don't specify a property in the class-mapping, it won't be copied.
  • With Gilead, the @ReadOnly transport annotation should suffice.

The side-benefit is that you don't need to change your data access layer (supposing you have one). Doesn't matter if you use a ORM or not, with a relational database or not.

jweyrich
+1  A: 

I'd use a permissions based approach:

  • Assign roles to users (e. g. admin user, logged in user, guest user, ...), and
  • associate those roles with permissions (e. g. can read name of person, can modify name of person - maybe further limiting that to certain persons etc.)

On each request from the client, perform a check on the server, if the user is allowed to perform that action. In the case of "creation dates", this is probably never allowed for anybody. So

  • if the request contains a creation date, you can show an error message or ignore the request...
  • if the request doesn't contain a creation date (usual case), you create the date on the server - or if the person already has a creation date, reuse that.

The client will usually specify the person by some kind of ID (can be null for a newly created person), which the server can use to look up existing persons. Tampering with the ID shouldn't matter, because the user can only modify data that is specified by his permissions anyway.

Special case:

If you actually have to use a creation date supplied the client, because you want to know a bit more exactly when the user has clicked, the only thing you can do is to check that the supplied creation date lies between the previous request and the current request. However, you'd have to take into account the clock difference between the server and the client. And you can't guarantee the precision.

Chris Lercher
This answer addresses mainly the generic part at the end of your question. With GWTRPC - if you want to send the entire Person object - you may want to allow that it contains a creation date, but either a) ignore it, or b) check, that it matches the one on the server.
Chris Lercher
+1  A: 

Why not make the fields private and only provide a getCreationDate() and no setCreationDate()?

Peter Tillemans
+1  A: 

You could just ignore the values for the immutable fields.
If that is not possible because of how your persistence mechanism is setup on the server, then when the request gets to the server, retrieve another instance of the POJO from the persistent store and populate the fields that are immutable with the ones you just got. That way of somebody tampered with some of the fields you do not care.

Of course encryption might be a solution also to help in avoiding tampering.

Romain Hippeau
+1  A: 

Split your objects into two parts. One contains just the fields which the client can edit. Send both objects to the client but only save the editable object when the client returns it. You can use inheritance here to make your life more simple.

If your mapping tool doesn't bend the way you want, implement a copy() method which copies all fields from one object to another. Then you can load a fresh instance of the object from your database, copy the editable fields into it and then save the modified object.

Aaron Digulla