Monkuar Posted December 17, 2014 Share Posted December 17, 2014 (edited) function wsProcessClientMessage($clientID, $opcode, &$data, $dataLength) { global $wsClients; // check opcodes if ($opcode == WS_OPCODE_PING) { // received ping message return wsSendClientMessage($clientID, WS_OPCODE_PONG, $data); } elseif ($opcode == WS_OPCODE_PONG) { // received pong message (it's valid if the server did not send a ping request for this pong message) if ($wsClients[$clientID][4] !== false) { $wsClients[$clientID][4] = false; } } elseif ($opcode == WS_OPCODE_CLOSE) { // received close message if (substr($data, 1, 1) !== false) { $array = unpack('na', substr($data, 0, 2)); $status = $array['a']; } else { $status = false; } if ($wsClients[$clientID][2] == WS_READY_STATE_CLOSING) { // the server already sent a close frame to the client, this is the client's close frame reply // (no need to send another close frame to the client) $wsClients[$clientID][2] = WS_READY_STATE_CLOSED; } else { // the server has not already sent a close frame to the client, send one now wsSendClientClose($clientID, WS_STATUS_NORMAL_CLOSE); } wsRemoveClient($clientID); } elseif ($opcode == WS_OPCODE_TEXT || $opcode == WS_OPCODE_BINARY) { // received text or binary message if (function_exists('wsOnMessage')) wsOnMessage($clientID, $data, $dataLength, $opcode == WS_OPCODE_BINARY); } else { // unknown opcode return false; } return true; } Okay, this is the code that processes the client messages. It's extracted from here: http://code.google.com/p/phpwebsocket/ and I use it. My problem is. I call a mysql select on a function via my websockets using this: cb.socket.send('LOOTITEM 2213123'); (The CB class just connects it to the socket and sends it off) But I have a problem. I can crash my own server, just by going into Google Chromes console tab and spamming this: cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123');cb.socket.send('LOOTITEM 2213123'); Then I press enter, and look at my console. And a shit ton of queries are instantly checked and then it pops and says: So, this is way bad. Because people can just do this and crash the server. I need to limit the requests to atleast 1 second. Any idea? Edited December 17, 2014 by Monkuar Quote Link to comment https://forums.phpfreaks.com/topic/293144-rate-limiting-in-php-websockets/ Share on other sites More sharing options...
kicken Posted December 17, 2014 Share Posted December 17, 2014 Sounds like you have a bug in your wsBuildClientFrame function which is causing it to go into a recursion loop. You should address that issue before adding rate limiting. To add rate limiting, you count the # of requests along with keeping track of a timestamp. On each request compare the current # of requests to the # at the last timestamp and see if it's above your limit. If so, deny the request. Something like this //$lastTimestamp = timestamp of last check //$lastCount = whatever $count was at last check $now = time(); $count++; $timeDiff = $now - $lastTimestamp; if ($timeDiff > 1){ //Ensure timestamps have changed $countDiff = $count - $lastCount; $lastTimestamp = $now; $lastCount = $count; if ($countDiff/$timeDiff > 5){ //if more than 5 requests per second denyRequest(); } } 1 Quote Link to comment https://forums.phpfreaks.com/topic/293144-rate-limiting-in-php-websockets/#findComment-1499884 Share on other sites More sharing options...
Monkuar Posted December 18, 2014 Author Share Posted December 18, 2014 Sounds like you have a bug in your wsBuildClientFrame function which is causing it to go into a recursion loop. You should address that issue before adding rate limiting. To add rate limiting, you count the # of requests along with keeping track of a timestamp. On each request compare the current # of requests to the # at the last timestamp and see if it's above your limit. If so, deny the request. Something like this //$lastTimestamp = timestamp of last check //$lastCount = whatever $count was at last check $now = time(); $count++; $timeDiff = $now - $lastTimestamp; if ($timeDiff > 1){ //Ensure timestamps have changed $countDiff = $count - $lastCount; $lastTimestamp = $now; $lastCount = $count; if ($countDiff/$timeDiff > 5){ //if more than 5 requests per second denyRequest(); } } I see. And for the denyRequest function just simply return or exit out the user? And this issue wouldn't be prevalent if I were using a more modern approach, like socket.io/node.js correct? Quote Link to comment https://forums.phpfreaks.com/topic/293144-rate-limiting-in-php-websockets/#findComment-1499944 Share on other sites More sharing options...
Monkuar Posted December 20, 2014 Author Share Posted December 20, 2014 (edited) Sounds like you have a bug in your wsBuildClientFrame function which is causing it to go into a recursion loop. You should address that issue before adding rate limiting. To add rate limiting, you count the # of requests along with keeping track of a timestamp. On each request compare the current # of requests to the # at the last timestamp and see if it's above your limit. If so, deny the request. Something like this //$lastTimestamp = timestamp of last check //$lastCount = whatever $count was at last check $now = time(); $count++; $timeDiff = $now - $lastTimestamp; if ($timeDiff > 1){ //Ensure timestamps have changed $countDiff = $count - $lastCount; $lastTimestamp = $now; $lastCount = $count; if ($countDiff/$timeDiff > 5){ //if more than 5 requests per second denyRequest(); } } Sorry to bump this thread, but I got a working version: function wsOnMessage($clientID, $message, $messageLength, $binary) { global $servername, $dbuser, $dbpassword, $dbname, $users, $db; // anti flood protection if($_SESSION['last_session_request'] > time() - 1){ // users will be redirected to this page if it makes requests faster than 2 seconds echo "Limit Reached... Simmer down!"; return false; }else{ echo $_SESSION['last_session_request']; } I got a working version working here: My question is: That return false works but it will stop the whole script? Which if other users are using will stop them as well right? How do I only target the specific client and user instead? Also, should I use microtime instead? You know, I can use "wsClose($clientID);" to kick them off. But what's stopping them from just refreshing? Edited December 20, 2014 by Monkuar Quote Link to comment https://forums.phpfreaks.com/topic/293144-rate-limiting-in-php-websockets/#findComment-1500207 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.