I am using the Zend Framework but my question is broadly about sessions / databases / auth (PHP MySQL).
Currently this is my approach to authentication:
1) User signs in, the details are checked in database.
- Standard stuff really.
2) If the details are correct only the user's unique ID is stored in the session and a security token (user unique ID + IP + Browser info + salt). The session in written to the filesystem.
I've been reading around and many are saying that storing stuff in sessions is not a good idea, and that you should really only write a unique ID which refers back to the user's details and a security token to prevent session hijacking. So this is the approach i've taken, i use to write the user's details in session, but i've moved that out. Wanted to know your opinions on this.
I'm keeping sessions in the filesystem since i don't run on multiple servers, and since i'm only writting a tiny tiny bit of data to sessions, i thought that performance would be greater keeping sessions in the filesystem to reduce load on the database. Once the session is written on authentication, it really is only read-only from then on.
3) The rest of the user's details (like subscription details, permissions, account info etc) are cached in the filesystem (this can always be easily moved to memory if i wanted even more performance).
So rather than keeping the user's details in session, the user's details are cached in the file system. I'm using Zend_Cache and the unique cache id is something like md5(/cache/auth/2892), the number is the unique id of the user. I guess the benefit of this method is that once the user is logged in, there is essentially not database queries being run to get the user's details. Just wonder if this approach is better than keeping the whole lot in session...
4) As the user moves throughout the site the only thing that is checked is the ID in the session and the security token.
So, overall the first question is 1) is the filesystem more efficient than a database for this purpose 2) have i taken enough security precautions 3) is separating user detail's from the session into a cached file a pointless task?
Thanks.
You're asking a range of things.
Sessions
Sessions in PHP are fast and efficient. Thousands of small disk-based sessions on a moderately up-to-date server is not going to be a performance bottleneck. Neither is writing your own handlers (very easy; the PHP manual has examples) to put it in a database.
About the only best-practice rules about sessions is: only give the web browser one thing, the session ID. Putting just the logged in userid in the session and retrieving those details from the DB when you need them is also best-practice. It also means that user information can be changed and they get it on the next page update.
It doesn't sound like you will have this problem but beware of just throwing a lot of stuff into a session. A few K of data (say, a few dozen scalars) is fine. Tossing many objects and large arrays of data in there will be noticed. If you do this for a specific page, remember to throw it away in the session once the page is done with it.
You may also want to implement your own login timeout with a session variable. The garbage collection settings in php.ini are intended for managing the storage of session data, not for doing login timeouts.
Caching
This is a complex topic and you will probably need to start gathering metrics (generally page load times) before implementing anything.
To implement any sort of caching, you do need to consider the lifetime of the data you're caching and how expensive re-generating it will be on a cache miss. Just throwing memcache at the problem is not a solution; you still need to understand your caching parameters and how memcache interprets them. This also applies to any persistent storage solution, including disk-based sessions, but I'm highlighting memcache because it is high-profile and has quite an aggressive expiry mechanism.
An often overlooked example is loading the same data from the database multiple times in a page: a good ORM will do that for you without relying on MySQL query caching. Another overlooked example are small queries that run on every page: caching these for just a few seconds on a moderately busy server and the database load will drop considerably.
Finally, caching at multiple levels is often much more effective and scalable than once because they can leverage each other's expiries. It also abstracts well: for example, hide it in your ORM and it's theoretically available invisibly and automatically for all your objects.
1) You can easily test which is faster by making a loop script. Anyway, a drawback with using the filesystem is that you need to update the cached file everytime you update the db. Copies of data is in general a bad thing. Also, unless you have millions of visitors I dont think there will be any practical diffrence regarding speed in any of the stratagies. And... not to forget, sessions are also stored in the filesystem. One file for each session.
Is a query faster then the filesystem: Depends. Is query caching enabled. In MySql it is by default, and than you might be lucky and only need a memory access. If not, the db needs to do a filesystem accass anyway. Second, how optimized is your query with index's. How buissy is the server harddisk.
3) Depends on the speed of fetching it from db. In general, caching can do magic to speed performance, but caching in memory would be even better by using memcached or something similar. In general i would avoid copies of the data in files. But of course, if it takes secods to query the data from the db, than go for filesystem caching. Also, if you have many users.. like 10.000+ you have to make some folder system, since putting 10.000 cached files in the same folder slows downs the accesstime...
Related
I have a site built on Symfony 2 that is basically made up of various applications. Once an application is selected, I store that application's ID in a session variable. Then for every page load for that application, the database is queried for the details of that application.
Wouldn't it be more efficient to just store the application details in the session variable instead of just the application ID?
What are the down sides of storing the application details in that way, are there any security risks I need to worry about?
Thanks a lot.
I do not recommend to store the app number at session at all. You deprive yourself from usage of shared HTTP caches with that approach http://symfony.com/doc/current/book/http_cache.html#public-vs-private-responses as all your requests become private cause a response depends on SESSION value.
If you will move the app number to the url or header or etc you will get a lot of space for optimizations.
Usage of the DB to a get app info is a quite good practice as you are able to enable doctrine's result cache for this queries to make them not impact of the app performance at all. http://doctrine-orm.readthedocs.org/en/latest/reference/caching.html#result-cache
Usage of the session to store app_id is bad practice but usage of the session to store the all app info is even worse as the number of session_ids is significant and you will store a lot of redundant information.
I've decided the best way to handle authentication for my apps is to write my own session handler from the ground up. Just like in Aliens, its the only way to be sure a thing is done the way you want it to be.
That being said, I've hit a bit of a roadblock when it comes to my fleshing out of the initial design. I was originally going to go with PHP's session handler in a hybrid fashion, but I'm worried about concurrency issues with my database. Here's what I was planning:
The first thing I'm doing is checking IPs (or possibly even sessions) to honeypot unauthorized attempts. I've written up some conditionals that sleep naughtiness. Big problem here is obviously WHERE to store my blacklist for optimal read speed.
session_id generates, hashed, and gets stored in $_SESSION[myid]. A separate piece of the same token gets stored in a second $_SESSION[mytoken]. The corresponding data is then stored in TABLE X which is a location I'm not settled on (which is the root of this question).
Each subsequent request then verifies the [myid] & [mytoken] are what we expect them to be, then reissues new credentials for the next request.
Depending on the status of the session, more obvious ACL functions could then be performed.
So that is a high level overview of my paranoid session handler. Here are the questions I'm really stuck on:
I. What's the optimal way of storing an IP ACL? Should I be writing/reading to hosts.deny? Are there any performance concerns with my methodology?
II. Does my MitM prevention method seem ok, or am I being overly paranoid with comparing multiple indexes? What's the best way to store this information so I don't run into brick walls at 80-100 users?
III. Am I hammering on my servers unnecessarily with constant session regeneration + writebacks? Is there a better way?
I'm writing this for a small application initially, but I'd prefer to keep it a reusable component I could share with the world, so I want to make sure I make it as accessible and safe as possible.
Thanks in advance!
Writing to hosts.deny
While this is a alright idea if you want to completely IP ban a user from your server, it will only work with a single server. Unless you have some kind of safe propagation across multiple servers (oh man, it sounds horrible already) you're going to be stuck on a single server forever.
You'll have to consider these points about using hosts.deny too:
Security: Opening up access to as important a file as hosts.deny to the web server user
Pain in the A: Managing multiple writes from different processes (denyhosts for example)
Pain in the A: Safely making amends to the file if you'd like to grant access to an IP that was previously banned at a later date
I'd suggest you simply ban the IP address on the application level in your application. You could even store the banned IP addresses in a central database so it can be shared by multiple subsystems with it still being enforced at the application level.
I. Optimal way of storing IP ACL would be pushing banned IP's to an SQL database, which does not suffer from concurrency problems like writing to files. Then an external script, on a regular basis or a trigger, may generate IPTABLES rules. You do not need to re-read your database on every access, you write only when you detect mis-behavior.
II. Fixation to IP is not a good thing on public Internet if you offer service to clients behind transparent proxies, or mobile devices - their IP changes. Let users chose in preferences, if they want this feature (depends on your audience, if they know what does the IP mean...). My solution is to generate unique token per (page) request, re-used in that page AJAX requests (not to step into a resource problem - random numbers, session data store, ...). The tokens I generate are stored within session and remembered for several minutes. This let's user open several tabs, go back and submit in an earlier opened tab. I do not bind to IP.
III. It depends... there is not enough data from you to answer. Above may perfectly suit your needs for ~500 user base coming to your site for 5 minutes a day, once. Or it may fit even for 1000 unique concurent users in a hour at a chat site/game - it depends on what your application is doing, and how well you cache data which can be cached.
Design well, test, benchmark. Test if session handling is your resource problem, and not something else. Good algorithms should not throw you into resource problems. DoS defense included, and it should not be an in-application code. Applications may hint to DoS prevention mechanisms what to do, and let the defense on specialized tools (see answer I.).
Anyway, if you get into a resource problems in future, the best way to get out is new hardware. It may sound rude or even incompetent to someone, but calculate price for new server in 6 months, practically 30% better, versus price for your work: pay $600 for new server and have additional 130% of horsepower, or pay yourself $100 monthly for improving by 5% (okay, improve by 40%, but if the week is worth $25 may seriously vary).
If you design from scratch, read https://www.owasp.org/index.php/Session_Management first, then search for session hijacking, session fixation and similar strings on Google.
This is a beginner question...
In a website, what type of data should or should not be included inside the session? I understand that I should not include any info that needs to remain secure. I'm more interested in programming best practice. For example, it is possible to include into the session some data which would otherwise be sent from page to page as dependency injection. Wouldn't that correspond to creating a global variable?
Generally speaking, what kind of data has or hasn't its place inside a session table?
Thanks,
JDelage
The minimum amount of information needed to maintain needed state information between requests.
You should treat your session as a write-once, read many storage. But one which is rather volatile - e.g. the state of your underlying application data should be consistent (or recoverable) if all the sessions suddenly disappeared.
There are some exceptions to this (normally the shopping basket would be stored in the session - but you might want to perform stock adjustments to 'reserve' items prior to checkout). Here items may be added/edited/changed multiple times - so its not really write-once - but by pre-reserving stock items you are maintaining the recoverabiltiy of the database - but an implication of this is that you should reverse the stock adjustments when the session expires in the absence of completion.
If you start trying to store information about the data relating to individual page turns, you're quickly going to get into problems when the user starts clicking on the forward/back buttons or opens a new window.
In general you can put anything you like in a session. It's bad practice to put information in a session that has to be present to make your page run without (technical) errors.
I suggest to minimize the amount of data in your session as much as possible.
stuff you can save in the session so that you dont have to make another database query for info that isn't going to change. like their username, address, phone number, account balance, security permissions on your site, etc.
(This is perhaps more than you're looking for, but might make for good additional information to add to the good answers already posted.)
Since you mention best practices, you may want to look into some projects/technologies which can be used to take the idea of session state a bit further. One common pitfall with horizontally scaling web applications across multiple servers is maintaining session state between them. (User A logs in to Server A which stores the user's session, but on the next request hits Server B which doesn't know about User A's session, etc.)
One of the things I always end up saying to myself and to colleagues is that session by itself isn't really the best place to store data, even if that data is highly transient in nature. A web server is a request/response system, not a data store. It's highly tuned to the former, but not always so great for the latter.
Thus, there are ways to externalize your application's session data (or any stateful data, which should really be kept to a design minimum in the RESTful stateless nature of the web) from your web server and to another system. Memcached is a very common tool for this. There are also drop-in session replacements (or configurable session options for various frameworks/environments) which store session in a database like SQL or MySQL.
One idea I've been toying with lately is to store session data (well, any transient data where it's OK to lose it in a catastrophe) in a NoSQL database. CouchDB and MongoDB are my current top choices for this, but there's no shortage of other options. CouchDB has excellent horizontal scaling, MongoDB is ridiculously fast when run entirely in-memory, etc.
One of the major benefits of something like this, at least for me, is that deployments can easily become non-events. The web services on any given server can be re-started and the applications therein re-initialized without losing stateful data. If the data is persisted to the disk (that is, not entirely run in-memory) then the server can even be rebooted without losing it. Servers/services can drop in and out of the farm and users would never know the difference.
Additionally, externalizing this data allows you to analyze the data in potentially useful ways. Query it, run metrics on it, interface with it via other web applications or entirely offline tools, etc. It really opens up the options as a project grows in complexity.
(Again, this isn't really intended to answer your question, but rather to just add information that you may find useful. It's something my colleagues and I have been tinkering with as of late and your question seemed like a good place to mention it.)
I'm playing around with creating a user login system in php.
I have been studying this article (http://www.evolt.org/node/60384) as a way of approaching this.
In the above article, the author uses a combination of $_SESSION and his own custom database table for storing user info.
However...
I have also come across numerous articles that recommend using session_set_save_handler to configure php sessions to use the database natively. (Which I guess is a newer technique.)
I am wondering: If I am planning on setting up an "activeUsers" table in the database for recording session data anyhow, does it make more sense to use session_set_save_handler? (Seems if I'm using the database to store some session info anyhow, I might as well dispense with filesystem sessions.)
Or is there some advantage to leaving php sessions in their default filesystem form, and then x-checking user logins against my custom db table?
Thanks (in advance) for your help.
Storing session data in a database can be a little tricky to setup at first, but once you have a class or function set up to do this, then you get a few potential advantages over filesystem storage. The question is whether or not those advantages are required for your system. These are, I think, amongst the most common reasons for storing session data in a database:
Security: If using shared hosting, session data may be held in areas of the disk that are accessible by other users of the system. This could constitute a security risk for your application.
Scalability: If your application is handled by more than one server (a server farm, for instance_, you need to ensure that multiple requests from the same client, which may be processed by different servers, each receive the same session data. This is quite easy to do if the session data is in a database.
Performance: Database storage may give a performance increase over filesystem storage, but this is heavily influenced by the server configuration.
DB interaction: Depending on the role of your session data, and how your application uses it, it may be easier to retrieve session data and related information if it is all in a database.
Something else to consider is that you can enhance the session information by storing additional information, such as IP addresses, log on and log off times, and so on. This sort of information can be useful when trying to prevent session hijacking.
So, other than the scalability issue, I think it's all quite subjective. You need to weight up the extra work required to implement database session storage, with the possible benefits.
If you use it you need to make your own garbage collector.
Hy guys. I'm currently working on a project which uses a lot of data stored in session variables. My question is how reliable is this method and if affects the server performance and memory usage. Basicaly, what you would choose between session variables and cookies.
In general, session variables are going to be a lot more secure in the fact that the user cannot edit them locally on his/her machine.
But the real question begs, what are you looking to store? With a bit more information we might be able to give you a better answer as to where you would want to store it :)
Edit:
If you are looking to store user actions, I might recommend building a UserActions table or something along those lines. A table that contains the following:
id INT (generic ID for the record),
timestamp TIMESTAMP/DATETIME (whatever your DB supports),
userid INT (lookup to the user table),
action VARCHAR (what action you want to record),
etc etc (whatever else you want to store)
Then when a user performs an action you want to record, just log it into the table itself, instead of making it travel along with the user in a session/cookie. Really the page itself doesn't need to know what actions the user has performed in the past, unless its a "multi-step wizard" type application. In that case, it probably would be best to pass them as a session variable.
Then you are pushing the storage into a true storage component (being the database) instead of session/cookie as storage.
I mean we still don't really have an idea of exactly what you are developing, but I hope it helps.
Session variables are generally preferable to cookies. That said, they are usually stored in the /tmp directory on your web server, which is world-readable and world-writable. This could be breeding ground for mischief if you don't control your server or you run in a shared environment. Not storing sensitive information in session variables, and not relying on them for stuff that has to work is a good practice.
You should only use cookies if you need the data-per-user to persist across sessions. That is to say, if they revisit the site outside of the session expiry time and you need the data there.
Otherwise, if the data is only for their current session, then go ahead and put it in $_SESSION. That what it's there for.
Session data is usually stored in files on the server or in database. So how many data is there depends only from your scripts. If you want to store big binary files in the sessions you will probably reach memory limits quickly.
Storing the data in cookies is not always a good idea. This data is visible to the client, he can easy change it and in some cases that just something you mustn't allow.
Session variables do not require submission by the user, they are simply loaded based on a session key. Memory usage depends on the session implementation since there is the cost of retrieving the session from your database (or file system, or memory, or w/e).
it's always a tradeoff between keeping information on the server (more memory used) and pushing some of that data off to the client machine (more bandwidth and less secure). As a rule of thumb, I prefer sessions, they are more secure and easy to manage.
When i wrote this question I was thinking at non-sensitive data and with application for logging user activity on website. I think that, for a busy server, with a large number of users, it's better to use cookies instead, it will unload the server resources(memory, hard-drive I/O). In terms of performance, I think that session variables are a better solution.
Anyway, I don't know how better it will scale the SV solution.
Using any session variables - at all - means that your application servers need to maintain session state with appropriate synchronisation.
This has an overhead and may negatively affect the scalability of your application, because every server needs to know about (potentially) every session - which is going to mean a lot of cross-server traffic for session data and synchronisation.
While you only have one server, it's ok.
When you get more and more servers geographically distributed, it gets more and more painful.
There is some overhead for the serialisation / unserialisation of the session, but in practice that's not such a problem as it will be relatively fixed per request, hence scalable to high traffic applications.