mxmbsocket/lib/Ratchet/Application/WebSocket/Version/Hixie76.php
Mike Almond 2996c08728 [REFACTOR] Fixing some code based on unit tests
Change the response to send the proper header and fix the generate key method to fail properly when no spaces are present
2012-02-01 13:16:59 -05:00

76 lines
3.0 KiB
PHP

<?php
namespace Ratchet\Application\WebSocket\Version;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
/**
* FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
* Hixie76 is bad for 2 (there's more) reasons:
* 1) The handshake is done in HTTP, which includes a key for signing in the body...
* BUT there is no Length defined in the header (as per HTTP spec) so the TCP buffer can't tell when the message is done!
* 2) By nature it's insecure. Google did a test study where they were able to do a
* man-in-the-middle attack on 10%-15% of the people who saw their ad who had a browser (currently only Safari) supporting the Hixie76 protocol.
* This was exploited by taking advantage of proxy servers in front of the user who ignored some HTTP headers in the handshake
* The Hixie76 is currently implemented by Safari
* Handshake from Andrea Giammarchi (http://webreflection.blogspot.com/2010/06/websocket-handshake-76-simplified.html)
* @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
*/
class Hixie76 implements VersionInterface {
public static function isProtocol(RequestInterface $request) {
return !(null === $request->getHeader('Sec-WebSocket-Key2'));
}
/**
* @param string
* @return string
* @todo Unhack this mess...or wait for Hixie to die (HURRY UP APPLE)
*/
public function handshake(RequestInterface $request) {
$body = $this->sign($request->getHeader('Sec-WebSocket-Key1'), $request->getHeader('Sec-WebSocket-Key2'), $request->getBody());
$headers = array(
'Upgrade' => 'WebSocket'
, 'Connection' => 'Upgrade'
, 'Sec-WebSocket-Origin' => $request->getHeader('Origin')
, 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host') . $request->getPath()
);
if ($request->getHeader('Sec-WebSocket-Protocol')) {
$headers['Sec-WebSocket-Protocol'] = $request->getHeader('Sec-WebSocket-Protocol');
}
$response = new \Guzzle\Http\Message\Response('HTTP/1.1 101 WebSocket Protocol Handshake', $headers, $body);
return $response;
}
public function newMessage() {
return new Hixie76\Message;
}
public function newFrame() {
return new Hixie76\Frame;
}
public function frame($message, $mask = true) {
return chr(0) . $message . chr(255);
}
public function generateKeyNumber($key) {
if (substr_count($key, ' ') == 0) {
return '';
}
$int = preg_replace('[\D]', '', $key) / substr_count($key, ' ');
return (is_int($int)) ? $int : '';
}
protected function sign($key1, $key2, $code) {
return md5(
pack('N', $this->generateKeyNumber($key1))
. pack('N', $this->generateKeyNumber($key2))
. $code
, true);
}
}