2

What are the advantages and disadvantages of placing session id in a hidden form input vs a cookie?

Is it correct to put CSRF-Tag in a hidden form input field and session id in an httpOnly cookie? Which is more secure?

Sherif
  • 11,786
  • 3
  • 32
  • 57
aLoneStrider
  • 343
  • 1
  • 6
  • 13

2 Answers2

5

If you put Session ID in a hidden form field, that is a lot more secure, however it can hamper the user experience.

The reason is that is this would inherently protect you against CSRF because any cross-domain requests made to your site will mean that the browser will not automatically include the session identifier that makes CSRF attacks possible. It also neutralises session fixation attacks as there is no cookie to poison. Additionally any Login CSRF is also dead in the water.

To implement this, you would have every action on your site, including navigation, to be actioned via the POST method. The GET method would be unsuitable because this would expose the session identifier in the browser history, in any proxy or server logs by default, and can also be leaked via the referer header.

For example,

<form method="post" action="/executeAction">

  <input type="hidden" name="sessionId" value="12345678901234567890" />
  <input type="hidden" name="action" value="navigateToAccountStatus" />

</form>

Note that this will prevent use of the back button without the user re-submitting the form (which could be dangerous if the action wasn't a safe action). To guard against this, you could refresh the session identifier after each action is processed.

Another reason is this will protect your site against attacks such as POODLE. As there are no cookies for a Man-In-The-Middle to brute force one byte at a time from, a POODLE attack would be fruitless.

Note that this approach is more difficult to implement, and not many web-frameworks support it as default.

Is it correct to put CSRF-Tag in form hidden field and Session Id in httpOnly cookie?

Yes, this is the approach most sites take. It is "secure enough" for most purposes - only very high security systems like online banking should take the form approach.

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
4

I don't think that one is inherently less secure than the other. Security is generally built in layers. By asserting that choice A can be more secure than choice B, when both choices play on the same vertical, you are asserting that security stops there. This is completely false and unsubstantiated in practice.

By passing around session ids primarily in the form of hidden form inputs you actually create more problems than you solve for yourself. Also, I disagree with the assertion that this in anyway makes you inherently protected from CSRF.

When you think about what purpose a session serves (retaining state between the server and client over an otherwise stateless protocol), it doesn't actually make sense to say I will pass all of my session ids via hidden input fields. Because, for one, not every request made to your server involves the use of a form. For another, the state is lost the moment the user refreshes the page or closes their browser. This isn't pragmatic at all.

It is correct to place CSRF tokens in hidden inputs. It's also not incorrect to send them along to the client via HTTP headers. The CSRF token by itself isn't enough to prevent the attack. What's also needed is that the server understands how to recognize that this toke, which was supposedly uniquely generated for this client, is not reused and not tied to another session by the same user.

Since generally a CSRF attack is based on the premise that you cannot distinguish the real user from the malicious forgery, the idea is to make the forger's job more difficult by regenerating the token for every request. Coupled with a use-only-once requirement and it doesn't actually matter anymore that the session is hijacked. So you really shouldn't try to solve this problem at the wrong level, by assuming that you can somehow solve both problems by relying on passing your session ids in hidden inputs and convincing yourself that this is more secure than storing the session id in a cookie. It's not. There should be additional layers of security to protect your sessions from session hijacking or session fixation attacks like using SSL only cookies, HSTS, and regnerating session ids (while deleting the old session files) upon re-authentication requests. Also, forcing re-authentication for user-level non-idempotent actions.

But please please don't assume that hidden input makes you inherently more secure from CSRF or Session Fixation, or any of these attacks. It doesn't!

Community
  • 1
  • 1
Sherif
  • 11,786
  • 3
  • 32
  • 57
  • `I disagree with the assertion that this in anyway makes you inherently protected from CSRF` - Could you explain how an attacker could accomplish a CSRF attack when Session ID is supplied in the POST body? If you cannot, then I can't see how you can disagree with this. – SilverlightFox Sep 11 '16 at 07:02
  • `not every request made to your server involves the use of a form` - The point is that you architect your system so that every request _is_ a form submission. This makes your system more secure also because you are locking down possible workflows, and therefore a user (or attacker) cannot easily circumvent business logic by e.g. submitting forms in the wrong order where assumptions have been made by the developer that previous stages have been correctly completed. – SilverlightFox Sep 11 '16 at 07:04
  • `the state is lost the moment the user refreshes the page or closes their browser` - In a high security system this is desirable. The session state, including the currently browsed page of the application can be tracked and the user automatically be logged out if the user "deviates from the good path" or when the browser is closed (in combination with anti-caching headers). Many banking applications employ per page tokens to achieve their desired security - also see [this answer[(http://stackoverflow.com/a/19705994/413180) – SilverlightFox Sep 11 '16 at 07:21
  • @SilverlightFox The same way they would accomplish a CSRF attack when the Session ID is supplied via cookies. You seem to be conflating the CSRF attack vector with other attack vectors. As if the two can't be dealt with separately. They can. In fact, trying to solve both at the same time just means you are *more* likely to make a mistake, not less. Build security in layers. It is not a one-shot deal. – Sherif Sep 11 '16 at 09:02
  • @SilverlightFox Sure, you can close off CSRF attack vectors by requiring the CSRF token with every request. Still no reason to have to pass session ids via the HTTP response body though. Just like you need not pass CSRF tokens via the HTTP response body. It's perfectly acceptable and secure to pass both of those things via HTTP headers as long as you have end-to-end encryption in place. – Sherif Sep 11 '16 at 09:08
  • 1
    Your sole focus here seems to be on security, which is great. Security is important. However, you've intentionally made the programmer's job harder, which just means the programmer is likely to make *more mistakes*, thus likely resulting in *worse security*. Don't forget the majority of successful security attacks on the web tend to bypass the most sophisticated and technically secure systems by attack the one thing prone to error (humans). Secure systems stop at the programmer's mistake. – Sherif Sep 11 '16 at 09:12
  • An attacker could not achieve CSRF because session cookies will not be sent because there aren't any. Please make sure you are not confusing this attack with XSS. I'm not saying it has to be passed in request body, but it is a perfectly valid session management solution. Many banks do this. As said, attacks like POODLE and similar attacks are also mitigated. – SilverlightFox Sep 11 '16 at 09:12
  • 1
    Yea, I'm definitely not confusing CSRF with XSS. Not sure where you arrived at such a ridiculous conclusion from anything I've said. Though note I'm not suggesting that you *can't* do it this way. I'm specifically saying you're intentionally making it harder to program with the ***same exact security benefits*** as those offered by the alternative approach. – Sherif Sep 11 '16 at 09:15
  • Security is hard. I agree that complexity often opposes security, however for a competent, security orientated developer this approach would be straight forward and easily tested. Look up "per page tokens". I recommend the Web Application Hacker's Handbook. – SilverlightFox Sep 11 '16 at 09:16
  • You seem to be assuming that by having a session cookie that the page is now automatically vulnerable to CSRF. This is entirely and completely unsubstantiated nonsense. Since the answer details how this same mitigation you propose in your answer of passing the session id along in the response and not via cookies, can also be mitigated in other ways that yield identical security benefits. – Sherif Sep 11 '16 at 09:17
  • 1
    You're just attacking this problem from a microscopic singular perspective, which isn't pragmatic at all. Your assumption that the average developer is even remotely competent in aspects of security is ludicrous. They aren't. Otherwise, you wouldn't see questions like this floating around all over the web. You need to approach the problem from the perspective that **the developer WILL make a mistake** not **if**. Because they ***will*** and when they do you ***absolutely need to have redundant layers of security*** to guard against that and act as a fail safe against the developer. – Sherif Sep 11 '16 at 09:20
  • None of this means you should make the developer's job **more difficult**. It's unnecessary to create *more secure* systems. You can actually create more security without creating unnecessarily complex development techniques. – Sherif Sep 11 '16 at 09:23
  • 1
    I've just read all of these comments and I still don't see a single argument how CSRF would be possible with hidden input fields. The session only exists within the current "window". Clicking on "Back", changing the url manually or opening a new tab will create a new (possibly empty) session, unrelated to the old one. How would you do CSRF here? – hasufell Jan 02 '17 at 10:39
  • @hasufell You are indeed correct, CSRF is not possible if the browser won't automatically send the session token. – SilverlightFox Feb 04 '17 at 23:49
  • @SilverlightFox CSRF is not possible here but you introduce problems with maintaining session management. Also this concept of treating EVERY request as if it were a form POST is a basic affront to the underlying HTTP application layer. The HTTP Verb is supposed to be analogous to a users action. The user may POST a form, or they may PUT a new entity to a REST service, or they may GET a web page. All of these actions may require stateful interaction with the server to ensure the user is authenticated and authorized to these actions. My counter is that your solution breaks the web. – maple_shaft May 26 '17 at 12:13
  • @maple_shaft: Read The Web Application Hacker's Handbook - What I am describing is "Per-Page Tokens" - this allows fine grained controls on a session. Implementation is not to be taken lightly - it is a highly secure solution of session management and requires skilled developers to implement. I realise the OP maybe wasn't after such a solution, however as it was relevant my answer was based upon it (the question is tagged "security" and this is a secure solution). It's not about "verbs of the web" it is about tracking what the client-side is up to server-side. – SilverlightFox May 26 '17 at 14:05
  • 1
    @maple_shaft: The web isn't secure by default - I agree this solution "stomps over" making RESTful implementations and the like, however it is not what it is about. It is about making a solid solution that can mitigate CSRF, session fixation, prevents hijacked sessions, tracking user sessions to the very page they are viewing and detection of access to pages outside of the defined sequences. – SilverlightFox May 26 '17 at 14:07