The scenario is this:
An iPhone app connects to a WebServer with Appache, PHP & MySQL.
The iPhone app has a timeout of 5 seconds on connections(Async NSURLConnection). IF the response from server comes after the timeout the application doesn't know and tries to send the data again.
On the server the php script runs twice. Once when the first set of data arrived. It creates a new user in the database but by the time it should echo the response the app timeouts. The second time the app tries to create the user it receives an error because the username should be unique. This happens because the first time the php script already inserted the user into the database.
In this case the user is created on the server but the user doesn't know this because he receives an error with user already created.
A few things:
- The timeout can be increased but it doesn't matter. The server can take even more to create the user when under load.
- I can test if the user can login and instead of trying to create I just login him normally. The problem here is what happens if two users try to create a user with the same username and password because in that case the second user will automatically login. In this case I can indeed add a check to see if the user was created in the last minute and just login if so. (The thing is if the script takes more than 1 minute to execute the server should crash first, the create user script takes 0.001 seconds to execute and under load it takes 3-4).
Is there any way to prevent a php script from executing if another one is executing with the same data? Or is there another solution to this problem?
I am not sure about the php route but one solution from the iPhone side is to include in your client's http request a vendor specific device identifier from UIDevice's identifierForVendor: This way you can identify whether the create request is coming from the same device (same iPhone user) or someone else. If this unique id does not match up, you can give your "Sorry, this username is taken" message.
As a side note though, if the users create a user with the same username and password then it is usually valid to assume it is the same user trying to log in on multiple devices (iPhone and iPad for example). This may be a use case that you want to support. The chance of two users independently trying to create the same user/password account is highly unlikely. It is less likely a scenario than the common scenario of someone randomly guessing a username/password combo and gaining access through that route. If you are using a username/password system the underlying assumption is that this represents an acceptable level of risk. Some strategies for minimizing this risk is to use password complexity rules, enforcing usernames to be valid and confirmed email addresses, and in extreme cases to use two factor(or more) authentication.
There is a device ID present in all iphones and they are all unique, verify on your language how are you going to get that once a user tried to register using their iphone. so using that device ID they cannot make registration more than one.
First choice is probably assume that they are the same user (or ought to pick better passwords) and let them in, as #Aaron says.
Two other possibilities, depending on how much duplicate users matters:
1) Use an email address and have them verify their user-create action. If you get a duplicate register request you can just put up a the same "see your email, click here to resend" screen.
2) Use database transactions to ensure that only one connection can login / register at the same time. Horrible scalability.
Related
I am using a simple PHP API that takes requests and connects to a MySQL DB to store/retrieve user information. Example: Login is done using a HTTP POST to the API with username and password.
How do I prevent people from flooding my API with requests, potentially making thousands of accounts in a few seconds.
Thanks
You could serve a token generated and remembered on the server side which is rendered with your forms and validated when the form is sent back to your server. That prevents the user from just generating new post requests without actually requesting the according form from your server since they need the according token generated on your server to get it through.
Then there is the mentioned captcha which would be way too much for a login form from my point but when it comes to things like registering a new user the captcha in combination with the token sounds very good to me.
UPDATE
I Just found this article which is about floot protection of script execution in general. I think their approach is good as is the ip tracking provided you have the ability to use memcache or something similar to speed the checks up.
First, when registering a user, also save her IP address at the time of registration in the DB.
If the IP already exists within 45 minutes of previous registration, reject the request.
Another method is the Captcha, I personally prefer a different method that I found to be even more effective against robots.
Instead of asking the user to "type what they see in an image", and verify they are humans (or robots with sophisticated image processing),
Add another field (for example city), and make it hidden with javascript.
The robots would submit that field to the server, and humans would not.
Note that the robots must run the javascript in order to know what fields are hidden, and this is a time consuming process that they usually don't do.
(see turing halting problem)
I have seen MANY questions on this before online in many places, however, out of about 30 forums and whatnot, NONE of them have had the solution I need, and that includes stackoverflow. If anyone could help me find a reliable solution, it would be greatly appreciated, so thanks in advance!
I'm going to explain my site and situation with as much detail as possible in order to help any who want to help answer my questions. Here is my situation:
I have a website and I use PHP and MySQL. My website is a "private" organization site. In order to allow people access to the site, I send new members of our organization and invite code. The user then visits the website, and the index.php file simply contains a form for logging in as well as a link to the registration pages. New members click the "Register Here" link to begin registration. The first registration page asks for the user's last name and invite code which are checked against a database to make sure that person is on the list and has not yet registered. If they pass the check, they are taken to the next page in which they enter required information (username & password, email address, etc.) as well as some optional information (phone, bio, etc.). If the user creates a valid username and password and has all required fields filled out, their information is stored in a database. Passwords are all salted and hashed properly and securely, so there is no problem there, and the whole registration process works as it should. After registering, the user is taken back to index.php where they can now log into using the username and password they just created. This works as well; when the user logs in, their username and password are checked against the database, and if successful, the user is logged in. When the user is logged in, an ONLINE value in the database is set from False to True. The user is now logged in and can use the site as it is intended. On my site, there is a column that lists users that are currently online (based on the ONLINE value from the database). When the user clicks the "Log Out" button which is located on every page of the site, the logout.php script is run, ending the session and setting the ONLINE value back to False. This all works fine and dandy, however, the problem comes when the user closes the browser without logging out first. This is where I have seen many different "solutions" various places on the internet. I am going to explain why they won't work and why I need a better solution.
The answers I see most often involve some sort of session timeout or destroying sessions, which is irrelevant because of the fact that the session already does, in fact, end when the user closes the browser, but that has no effect on telling other users whether or not that person is currently online. When the session ends, the database won't be updated, which causes a problem due to the fact that a user can only be logged in from a single instance. If a user attempts to log in while their ONLINE value is already set to TRUE, they aren't allowed to log in.
I have also seen suggestions of using a "Last Seen" value instead of an online value, and if a user hasn't had any activity within the past x amount of minutes, log the user out. This won't work, however, for two reasons. 1) That script still has to be running somewhere in order for that to work, meaning another user must be logged in for that to work. That basically means that, if using this method, if a user closes their browser or if they loose connection, they won't be able to log back in until another user logs in. With my organization being a small, locally based organization as it is, there are likely to be many times in which there are no users online. Also, even if another user is logged in, the user whose connection was lost still won't be able to log back in until after x amount of minutes has passed, so if the user accidentally closed their browser and wanted to log back in immediately, they simply wouldn't be able to.
A less frequent solution I came across involved using the onBeforeUnload JavaScript function, but those most definitely will not work due to the fact that those would trigger any time a user clicked on a link or on the "Back" and "Forward" buttons. Also, if the user has JavaScript disabled in their browser, this will not work at all.
The last thing I have seen involves while loops and the connection_aborted function, and this is the only one that seems like it could work, yet I have not seen a very clear description of how this should work, and after spending months experimenting with it, I still have not come up with a reliable solution.
In many forums, I have seen people say that "it's not possible," but that can't be the case considering there are sites that do it somehow. I have tested and experimented with this on several sites. On a site that has users such as Facebook or any forum website, there is a list of "online" users, and in the case that a user closed their browser, their name would no longer appear on the list, so it is possible, even if it can only be achieved through some obscure method. So, if anyone knows of a solution, I would greatly appreciate if you could share some of your wisdom on this subject!
Try creating a Heartbeat mechanism in javascript.
this method would start sending an ajax call to your webmethod on timely basis use.
setInterval(function(){
sendPulse();
},30000);
sendPulse(){
var varUserID = userID;//any unique user identifier that can be found on server side
$.ajax({
url: "Default.php/updateUserStatus",
UserID: varUserID,
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (mydata) {
//alert("pulse sent");
}
});
}
On server side, you must have a method with same name and case sensitive parameter. the should be static and marked as webmethod. in this method save the current time for the user. you should have a mechanism to know what users have very old pulse, do this check when a user tries to do something or performs any operation. I have implemented this approach and works very well.
That's the answer: persistent connection between client and server. For this, you will need a TCP connection, like websockets nowadays, or a flash old duplex connection. From here on, TCP takes care of noticing you when someone connects or disconnects. What you got to do is a websocket server (for example) who just traks connections (push and pop from an array), and also a way to respond to a "get_users_online" message. You can access your user's session (read only) via the websocket server, and then see if the user is logged-in (and in this way, you can store his nickname in session, access further from websocket server), see if he is admin (session->is_admin).
Pretty simple, I would say.
Here is the library I've been using: http://socketo.me/ . It uses a library for decoding symfony2 sessions, but for simple applications, you don't need decoding (symfony2 applications encodes sessions, so the websocket server has to decode them).
Big note: Sessions has to be stored externally (not in file system /tmp) like a ORM or NoSql.
Either way, escuse me, but I have to say that that the "Last time" seen is super okey. Most of the sites rely on this. You understood something wrong, you don't need to have a living server for checking "Last time" always, when you request /admin.php?users_online=1 , you make a query where "Last seen > NOW() - 5 minutes" (won't work written like that), so you can even get rid of the "ONLINE" "OFFLINE" field.
I suggest using a websocket approach, it's fun. :)
Good luck!
I have a working php application in which I want to add real-time support. I would like to use nodejs/socket.io to add that kind of functionality.
First problem I found was how to properly authorize user on nodejs side (user is already authenticated on php backend through PHP session). Using socket.handshake.header.cookie on nodejs side i can parse and get PHP session id, which I can authenticate through redis/memcache/database (depending on what have I used to save session information). Everything looks cool when user has only one tab/window of the site opened - when having more and using session_regenerate_id(), in nodejs the user authenticates with another sessionid key, so I cannot distinguish two tabs by anything other than the socket id they connected with. When user logouts he shouldn't be getting any messages on any tab (because he already logged out on every tab/window from that browser). So on logout message (sent from browser just before the logout PHP things) I should remove all the socket connections connected to the authorized user id. But what if user logges in on two devices (fe. pc browser and an ipad safaris). After logout on one device, he shouldn't be getting any messages on the device he logged out, not on every device. How can i distinguish connections from different devices/browsers in socket.io? Of course not using session_regenerate_id() would be efficent here, but what can I do if I really want to use this feature?
Another problem I have is rather a security issue (or even question). Let's assume that authorized user in application can see page example.com/user1 (which is a news feed for user1) and cannot see example.com/user2 (fe. he doesn't have rights to see it). I'd like socket.io to send update messages to browser when user is on example.com/user1, and of course not to send when user is on example.com/user2 site. On socket.io side I can read the referer address (so presumably, when user is on user2 site he does not get any socket.io connection). The question is: should I compare the referer address with the rights of authenticated user on node.js side? Or maybe the referer value is safe on the node.js side? Adding another db check on node.js side would slow it down (because almost every request there should be same database check on two sides - PHP and node.js).
Or maybe the whole concept of socket.io + PHP application working the way I presented is wrong?
UPDATE
I think I found a way to omit problems with the first question - basically I just add another cookie (besides PHPSESSID) fe. named NODESESSID, which I generate (fe. using uniqid()) when user is authorized. Now authorization on node.js side is comparing PHPSESSID and NODESESSID (both must match). Now, when user logges out he delivers the message logout to socket.io and socket.io disconnects all the sockets with NODESESSID. This is like connecting the benefits of regenerating session id and not regenerating session id (but is not vulnerable to session fixation, isn't it?).
For your second questions:
the Referer is not secure, as mentioned in the comments.
I hava a similar problem in my application and this is how it works for me.
first, i hava a single-page app where all traffic goes through the socket, but thats not necessary. it should work with sessions the way you managed it, too.
in nodejs onConnect I ask the backend if the user is authenticated and then store the userid into the socket object (socket.data) and also populate a hashmap to lookup sockets from userids directly.
second, i use Redis and subscribe to a redis list from nodejs (see redis pub/sub). the php backend pushes messages in this list with a userid to address the message. nodejs takes this message (e.g. a new news feed item), looks up the userid in the mentioned hashmap and sends it to the client. so, a user only gets what he is authorized for. the client then decides what to do with the message. if the user is on his feed page, it could add the item. if the user is on someone elses feed, it could simply add a notification somewhere else on the page. it might also discard it.
on the php backend site, this messages are send to redis everytime an event occurs which needs to be shown live on some connected client. if user1 posts on user2's feed, the new item is stored in the database and in the same time is send as message into the redis queue.
this system also helps to reduce DB load since nodejs just need to query a database to make sure the connected user is already authenticated.
Actually, you can avoid using node.js, and use phpdaemon, its written with php and work very good.
I have a social website in developmenti n PHP codeignitor and MySQL. I am storing user sessions in the database to handle a multi-server enviornment. Currently there is only 1 database.
1) To handle multiple databases (+ the multi server) how and where will the user session be stored? I assume database wont work in a multi-database env.
2) The session ID given to the user, is it an auto increament from the database or generated from the application logic? I assume it should be a GUID?
3) Along with the session ID I have a user_session table which logs all session related details like login_datetime, logout_Datatime, if user was on web/mobile, etc. So this table has to be written to in 2 stages: When the user logs in and again when the user logsoff. The questions is when the user logsoff what is the logic the system should follow to write the date? Like how will the system know which user_session to write the data to since this PK ID is a database driven autoincreament value and created after the main session ID is created. So at end it will need to query user_session table to find the user_Session ID and then write.
Your comment gave me some clues about the best way to solve this problem for you.
First, if the site is launching soon but not live yet, the best way to solve your problem is: don't worry about this problem yet. Just host everything on one server with one database for the time being. Your idea, no matter how brilliant, will need to solve lots of problems with its first few real users before demand picks up enough to require more hardware.
Second, your image and video servers probably don't need a user's session information. If a user requests a web page with a video, and they have enough access to view the web page, then you can probably just send along the video without further auth checking. This choice will also enable you to use a content delivery network (I personally like RackSpace Cloudfiles, with has a partnership with Akamai) for a much-improved user experience over using your own servers.
Good luck!
I have some ideas about it but very basic and not complete. I wonder what is the best way to check if same PC/IP is logged with two different users and runs two instances of my website?
If two users have the same IP, they are either
on the same computer
in the same household, office or company with a shared internet connection
in the same Internet café
this is as far as you can get. Reliably detecting whether two sessions are on the same computer is close to impossible, as there is no metric that could help you tell.
If you want to battle fraud, you will need to use different methods.
First, let the server send a unique token (e.g. csrf token) when the page loads and each time the user interacts. Then, let each user interaction (post or request) include this token (and generate a new one).
When you get unexpected tokens from the same IP adress, you apply a second trick: add the mousevent timestamps to the request and log (to the millisecond) the time differences (henceforth dt) between the local server time and the timestamp that came with the token, with a certain error margin for the variation in delaytime.
In the case two instances are running on the same PC, dt will be equal for both unique tokens (that were generated during the most recent interaction or pageloading).
On another physical computer, the chance that the dt is the same (even within the error margin) as on another pc on the same IP adress is extremely small, so that you have a valid way of testing.
you can check the ip-address, user-agent, time-zone, activated plugins...
To avoid more than one users logged in from the same computer you can set cookies or transmit a session key on every link. (you have to combine the hash with the ip-address an user-information you get because of copying the link should not log in other users into the account the hash belongs to)