Dean Vaessen Dean Vaessen - 3 months ago 14
reST (reStructuredText) Question

Preventing user manipulation exploit of REST URLs

I'm trying to figure out how I should prevent an exploit where the user modifies the URL of -for example- a GET request. The code below is a route on my Express router that handles the incoming request to go into a collection, let's say for the sake of argument it's collection "A", and returns the a few things from that collection.

router.get("/word/:collection/:language/:amount", function(req, res) {
getItems(req, res);
}


Now, if the user changes the
:collection
section in the URL in the front-end Javascript code to "B", he will get collection "B". How do I prevent this? In the case of things like collections that hold the userIDs I can just bar them from accessing these based on
req.user
(I think?) but in this case I can't do that because the user does need to have access to both collection A and B, I just want to restrict them from going in there at the wrong time (both are needed on different pages).

Answer

Rest endpoints that contain information only certain users should have access to need be secured. (The most common method being an API token being passed to the API, oAuth tokens, or a login cookie). If userA should not be accessing collectionB, you need to do a check within that resource, and return some type of error code to the browser.

The standard error most website's implement is 401: Unauthorized. Here's a simple example:

router.get("/word/:collection/:language/:amount", function(req, res) {
    if ( !hasAccess(req.params.userToken) )
    {
        return res.send(401, {success: false, message: 'no permission'});
    }
    var collection = req.params.collection,
    var language = req.params.language,
    var amount = req.params.amount;
    return getItems(req, res, collection, language, amount);
}

Edit: After rereading your question, I now realize that the user will need to have access to both collections at one point or another. In this case, you'll still need to implement some server side validation. Here's another example (With quizzes/answers):

router.get("/quiz/finish/:id", function(req, res) {
    //Store that this user has taken this quiz
    return recordQuizAnswers(req.params.userToken, req.params.quizAnswers);
}

router.get("/quiz/answers/:id", function(req, res) {
    //Has this user taken this quiz?
    if ( !hasUserTakenQuiz(req.params.userToken) )
    {
        return res.send(401, {success: false, message: 'Trying to get the answers before taking the quiz? Cheater...'});
    }
    return getQuizAnswers(req.params.id);
}

Edit 2: After seeing your comment, I've thought of another solution that you can use. Use UUID's for id's instead of auto-incrementing numbers. This will prevent the user from simply adding/subtracting to get different quizzes.