I am writing a server where I have an entity StoreOwner that "owns" or has a @OneToMany relationship to a Store entity (one store owner has 1 to N stores). Each Store has Offer and Item, each also have a @OneToMany relationship with the store (one store has 1 to N offers and 1 to N items).

I am already using GWT Xsrf protection and a session ID that gets associated with the logged in user after each log-in (cookie).

There's one thing missing IMHO: what if a logged in user sends a delete request to the server with IDs of items that he does not own of a store he does not own either? At the moment, I am doing this in my StoreService:

// StoreService.java

@Transactional
public ItemDTO deleteItem(String sessionId, Long storeId, ItemDTO itemDto) {

    // sessionId is the cookie I have placed in my database
    // This way I want to ensure that I am only accessing a store
    // that is associated with the logged in store owner (the user basically)
    Store store = this.storeOwnerRepository.getStore(sessionId, storeId);

    Item item = ConvertDTO.convertItem(store, itemDto);

    // Check if the store ID that I got using the cookie is the
    // same ID as the store ID from the item that should be deleted
    if(item .getStore().getId() == store.getId()) {
        item = this.storeOwnerRepository.deleteItem(item);
    } else {
        // If this didn't work we have a potentially hostile user:
        throw new RuntimeException("Is somebody trying to delete items of a store he doesn't own?");
    }

    itemDto = ConvertEntity.convertItem(item);
    return itemDto;
}

It is the first time that I am trying to write a bigger server application and I want to prevent users from doing such things.

My question is twofold: [1] does what I am doing would really prevent a logged in user from smuggling the IDs of another store he does not own to my server? In addition, [2] can I simplify this a little bit?

My problem is that as the application grows one might - every now and then - forget this check

if(item .getStore().getId() == store.getId()) { /* .. */ }

Of course, I could move that into my StoreOwnerRepository, but do I have better options?

  • 3
    Declarative security is generally simpler and less error prone than the programmatic security that you are currently using. Spring security, mentioned in @NeilMcGuigan's answer, supports declarative security and will generally be less error prone. – Neil Smithline Sep 10 '15 at 3:31
  • @NeilSmithline Thanks for the hint! Spring Security it is! :) – Stefan Falk Sep 10 '15 at 10:29
up vote 12 down vote accepted

This is called Access Control.

You need to check that a user has access to a record before performing an operation on it.

The simplest method would be to use a different database or schema per tenant. Or...

As you use Java, you could use Spring Security. It now integrates with Spring Data JPA, allowing you to pass in the userid/username into your SQL queries easily.

Or use Row Security right in the database. Oracle if you have $10M to spare, or this will be available for PostgreSQL in October. You can mimic it with updateable security_barrier CHECK OPTION views as of PG 9.4. For this you'd have to have the web server tell the db server the name of the current user.

You probably want to add an owner_id column to your "child" tables. Use an on update cascade foreign key to the parent table.

  • Hi! Maybe you can help me a little out here again. I am not sure if I'm getting it how to do what I needed in my question with Spring Security. I understand how Spring Security can help me to determine if a user has the role to e.g. delete or modify something but I don't understand how to use it to determine that the resource belongs in fact to another user. – Stefan Falk Sep 18 '15 at 17:12

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.