I am building a simple Q&A app with PHP, HTML and JS. I have three tables: users,question and answers, each table has it's own primary key and questions and answers both have foreign key constraints. questions store users.uID to look up author, and answers store question.qIDto identify which question they belong to, and also author that wrote the answer, so users.uID is also foreign key.

And here is my main concern: how to properly implement submit button for answer, that passes the author ID and also question ID that is supposed to be inserted in answers table via ajax request, so it has to get that ID from somewhere. The main concern is not XSRF, but the fact that authorised user could tamper with it, by changing a part of html code if the ID is stored visibly (or invisibly) somewhere.

User ID is easy, that can be stored in session once retrieved from DB and user logs in and will be reused elsewhere too so no big deal in term of performance costs, and can be accessed by all scripts while hidden from user. But also storing the question ID in session, each time user visits a question, and then replacing that with another question ID when he visits another question seems to me like it is asking for causing heavy load on server at some point.

Adding hash to the submit button, that is then validated by script that processes the ajax call data looks cumbersome to me too, since you have to store that hash in session too. And using hidden field is not safe either, since user can see that field in source code and can tamper with it.

So where to efficiently store that question ID, so it is ready when the submit button is pressed and also that user cannot tamper with it, and send ajax call with other ID? Is the session really only option?

  • FYI: This site uses a hidden field to indicate the question that an answer relates to. Commented Dec 14, 2016 at 11:35
  • why is it in the interest of the user to submit an answer to a different question to the one which is being asked?
    – Ewan
    Commented Dec 14, 2016 at 12:37
  • 2
    @Ewan That is just obviously the edge case, when 1% user just likes to tinkerˇand have "fun" with the site. He causes no real harm or damage, but still, someone has to clean up after him when he is done playing
    – The Law
    Commented Dec 14, 2016 at 12:47
  • im trying to understand the scenario you are attempting to prevent. answering the same question twice? overwriting an existing answer? there doesn't seem to be anything you need the quesitonid to be secret for. you can always apply your logic once you receive the answer on the server
    – Ewan
    Commented Dec 14, 2016 at 12:50
  • 1
    sure. but presumably he can achieve the exact same thing by selecting the 'how do i swim' question and typing the answer
    – Ewan
    Commented Dec 14, 2016 at 12:55

2 Answers 2


The main concern is not XSRF, but the fact that authorised user could tamper with it, by changing a part of html code if the ID is stored visibly (or invisibly) somewhere.

I understand the desire to make sure that the user does not circumvent the user interface you provided. However, this is not easy to do, and will not result in any improved security.

  • You would have to store the relevant user state server-side and compare it with the state provided by the user. Since the same state is now in two places, there's always the possibility that these states fall out of sync, e.g. if the user aborts an action or if the network connection is interrupted. The user may also have multiple states, e.g. if they are using your web app in multiple browser tabs.
  • You could also create a cryptographic signature of the user state, and give the user this signature as a token. The user must transmit the token with each request, so that it can be validated by the server. However, there's still the possibility of replay attacks if this token isn't implemented as a nonce.

All of that is easy to get wrong, and may cause a lot of frustration for your users if it doesn't work as intended (I've encountered a couple of sites that are sometimes unusable unless I delete some cookies). This effort is certainly justified for online banking or similar problem domains where you'd rather be safe than sorry. In other domains, this is more likely to be perceived as user-hostile.

Instead of checking that the user sticks to the links you provided, check that the user has the necessary permissions for any action they are trying to take.

  • If they are generally allowed to view, create, or modify a resource, allow the user to take that action even if they manipulated the URL.
  • If they are not allowed to access the resource, deny them even if they can guess the correct URL. A number of data “breaches” had the cause that private data was not protected by a permission model, but only by a “secret” ID that other users weren't supposed to know – but could be guessed or intercepted by the attacker.

To defend against abuse of the resources that user is allowed to access:

  • Use rate limits. E.g. in a Q&A system, a normal user can't and shouldn't post 5 answers within 10 minutes.

  • Develop a system for flagging and review of user-generated content, especially if user content is publicly visible.

  • If users are resorting to bots when using your web app, this could mean that you are lacking some crucial functionality. Offer an API that is more convenient than scraping. Sometimes, an export-to-CSV button is all your users are missing.

  • Your logic and explanation makes a lot of sense, "if user causes no real harm, it is probably not worth troubling yourself with too much". Going to accept your answer
    – The Law
    Commented Dec 14, 2016 at 18:03

Encrypt all "important" data on the server, and store the encrypted value in a hidden field. You can expose the same data in non-encrypted form if the client-side scripts need to use it.

And don't be afraid of "heavy load on server." There are many ways to scale, and load on the database is probably going to be your primary concern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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