csrf performance impact on database sessions

113 views
Skip to first unread message

Vahrokh Vain

unread,
Oct 18, 2016, 3:35:26 PM10/18/16
to Fat-Free Framework
Hello,

As you might have imagined by my plethora of similar questions, I am always working hard to squeeze the most performance possible .out of f3 .

I have read some tutorials about csrf management, it looks like the workflow is like this:

1) Call database session's csrf().
2) Store the returned value inside the session
3) Output / return the value in some form hidden field or similar
4) When the form is posted, check if the provided csrf  == value stored at step 2.

If this is the way to go, every http request requires a database write. This is going to snowball pretty fast in case of some hundreds of concurrent users (that is, my current software requirement).

As of now, I had to reduce the writes by requiring a csrf recalc only at certain key points.
However I am not sure this is going provide sufficient security to the software.

Anyone else got into this issue? Any idea about how I could improve / optimize it?

Thanks in advance.

Summer White

unread,
Oct 18, 2016, 6:15:57 PM10/18/16
to Fat-Free Framework
I havn't done this sort of thing before but I completely understand the concept. Thinking about it myself, if I had a contact form for example that I wanted to protect against illegitimate sources, I'd probably make it as difficult to post too as possible. But that's not to say that I wouldn't make it technically impossible. Just very improbable that someone would be bothered to develop an implementation for it. In other words, impractical.

So I would develop a lot of trade offs into my implementation for performance rather than security.

On the other hand, if you just wanted to talk about the performance aspect in the context of being forced to make database writes, why not write to memory instead of a physical disk using things like memcache.

But really the devils in the details and it really depends on the application of the form. If its a contact form, then about 99% of visits are unlikely to POST to that form anyway. If its a registration form, that would increase but why not use a captcha instead.

Let me know if I'm out of context to what you are talking about though.

Vahrokh Vain

unread,
Oct 18, 2016, 6:22:50 PM10/18/16
to Fat-Free Framework
Hello,

It's a software meant to be used by up to 3000 people. One of the most stringent constraints is that it's to be used by such "zero knowledge" people (i.e. warehouse laborers) that even login / logout has to be required max once a month.
I am never going to have a memory repository survive server upgrade / reboots over one month. People are going to write personnel cards, worked hours, some financial data. There's definitely more sensible data being stored here and way more often than a contact form.

Summer White

unread,
Oct 18, 2016, 10:27:41 PM10/18/16
to f3-fra...@googlegroups.com
Do you know what I mean though? If you want to generate a token for every single http request and write that onto the hard drive then there is no way around it. You'll always have that overhead no?

I'm not a performance expert though but my approach would be to make a trade off somewhere.

What forms are you trying to protect though? Would you have an authentication system or is this a purely public setup?

edit: spelling

Vahrokh Vain

unread,
Oct 19, 2016, 3:28:49 AM10/19/16
to Fat-Free Framework
Hello,

The software starts with a login form (if users is not logged on). Everything is only available exclusively after logging on, it's about 200 forms. Close to everything (90%) needs to be protected and contains sensitive data.

ikkez

unread,
Oct 19, 2016, 5:10:01 AM10/19/16
to f3-fra...@googlegroups.com
Well if you think that this is not the best solution, we're open for other ideas.
I could imagine, that in your case you could create a <form> tag handler for the template engine, which will create and store a unique form token, that is included in the html and stored in the session once you visit that page. So you only write into the session on pages that got a form. I had that idea already a while ago, but didn't needed that yet. I could dig on my desk for a code sample, if you need such a thing.

Of course you can also just create and handle such csrf tokens in your controllers, that render and proceed your forms.

Summer White

unread,
Oct 19, 2016, 6:15:01 AM10/19/16
to f3-fra...@googlegroups.com
So if their is authenticating users and tracking their session, then you needn't worry further about cross site forgery. You would of cause put in further protective measures such as ensuring a form isn't posted too (x) amount of times, and do plenty of validation.

I often throttle users who begin making too many requests, such as 30 requests a minutes. If it persists I just continue to throttle until it becomes unbearable slow. Its a cheap solution to make sure they arn't brute forcing anything. If such an event happened it would be flagged and I would investigate further. (Never has though).

edit: wrong words

ved

unread,
Oct 19, 2016, 8:26:24 AM10/19/16
to Fat-Free Framework
If the database is too slow and memcache/apc is too volatile, that seems like a good job for Redis.

PHP has native Redis support for sessions or alternatively you can setup F3 to use redis as cache handler and use cache based sessions.

Vahrokh Vain

unread,
Oct 19, 2016, 8:34:54 AM10/19/16
to f3-fra...@googlegroups.com
@Ikkez

Well,

there are two solutions I have implemented so far:

1) I am going the "Wordpress way", I am only regenerating a new csrf before rendering critical sensitive data forms. In example: I won't regen a csrf when showing a "select a company name from this list" (and other stuff) selection page but I will regen it when editing a specific company's data.

2) "PHP session garbage collection way": I am only regenerating a new csrf basing on random probability. I call a function that accepts a regeneration probability from 1 to 100%. Critical pages call it with 100(%), other pages could call it with 10, 20(%) and so on. That's going to be the probability of a new csrf code being generated and checked later. If regeneration did not took place, csrf stays the same and no database write is needed.

Vahrokh Vain

unread,
Oct 20, 2016, 7:14:32 AM10/20/16
to Fat-Free Framework
I got a third idea draft in mind.

Either with an explicit parameter or In case F3 detects disk based sessions and memcache(d) or similar is available, then:

1) If it does not exist yet, create a csrf key in memcache(d) or similar. This is the varying portion. Key is going to be stored in the database like csrf does.
2) Store the key hash in the session.
3) If / when a session write for other values occurs (that is, session write() is called), then update the database csrf with the memcached csrf key value.
4) Same for when garbage collection happens, if possible. The function would scan and update all valid session records and "sync" the disk stored csrfs with the ones in memory
5) Outside of 3 and 4, only write to the memcache(d) csrf. The idea is to keep rewriting a csrf on memory and lazy sync it with the corresponding database csrf.
6) Add a function (possibly the same that gets called in 4) that can be assigned a route and be called from the CLI. This route is meant to be called by cron and maybe at server shutdown.

Yes it's a lot of stuff, if I see our app is going to struggle too much with the solutions I have posted earlier, I am going to implement something like this.

ved

unread,
Oct 20, 2016, 8:41:10 AM10/20/16
to Fat-Free Framework
Wow, that seems complicated and unneeded. I honestly think you're trying to "prematurely optimize" your app and making things more complicated that they need to be.

Have you already stress tested the app to see if you really need it? The milliseconds you'll gain with this csrf thing could probably be dwarfed compared with other optimizations you could do like adding Redis (or Memcached if strings are enough) to your stack or upgrading to php7 or migrating your webserver to Nginx for example (in case you're still not using them).

If the issue is with using F3's csrf (that's tied to the session handler, in your case, the database) then you can just not use that crsf method and implement your own. On form display, create random string and store it in apc/memcached/redis. On form submit, compare with stored value. No database reads or writes, no F3 core refactoring and no file/memcache detection thingie needed.

Besides, if you really need top performance, you shouldn't be using the database session handler in the first place imho. Not that the issues you mentioned aren't valid or that performance optimization isn't needed, it just seems to be making you waste valuable time because of some extra db writes/reads that could be completely avoided.
Reply all
Reply to author
Forward
0 new messages