
Allowed user to disable WebSocket versions Change how versions are detected, responsibility is on the concrete version class instead of factory
74 lines
3.1 KiB
PHP
74 lines
3.1 KiB
PHP
<?php
|
|
namespace Ratchet\Application\WebSocket\Version;
|
|
|
|
/**
|
|
* 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 add 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(array $headers) {
|
|
return isset($headers['Sec-Websocket-Key2']);
|
|
}
|
|
|
|
/**
|
|
* @param string
|
|
* @return string
|
|
*/
|
|
public function handshake($message) {
|
|
$buffer = $message;
|
|
$resource = $host = $origin = $key1 = $key2 = $protocol = $code = $handshake = null;
|
|
|
|
preg_match('#GET (.*?) HTTP#', $buffer, $match) && $resource = $match[1];
|
|
preg_match("#Host: (.*?)\r\n#", $buffer, $match) && $host = $match[1];
|
|
preg_match("#Sec-WebSocket-Key1: (.*?)\r\n#", $buffer, $match) && $key1 = $match[1];
|
|
preg_match("#Sec-WebSocket-Key2: (.*?)\r\n#", $buffer, $match) && $key2 = $match[1];
|
|
preg_match("#Sec-WebSocket-Protocol: (.*?)\r\n#", $buffer, $match) && $protocol = $match[1];
|
|
preg_match("#Origin: (.*?)\r\n#", $buffer, $match) && $origin = $match[1];
|
|
preg_match("#\r\n(.*?)\$#", $buffer, $match) && $code = $match[1];
|
|
|
|
return "HTTP/1.1 101 WebSocket Protocol Handshake\r\n".
|
|
"Upgrade: WebSocket\r\n"
|
|
. "Connection: Upgrade\r\n"
|
|
. "Sec-WebSocket-Origin: {$origin}\r\n"
|
|
. "Sec-WebSocket-Location: ws://{$host}{$resource}\r\n"
|
|
. ($protocol ? "Sec-WebSocket-Protocol: {$protocol}\r\n" : "")
|
|
. "\r\n"
|
|
. $this->_createHandshakeThingy($key1, $key2, $code)
|
|
;
|
|
}
|
|
|
|
public function newMessage() {
|
|
return new Hixie76\Message;
|
|
}
|
|
|
|
public function newFrame() {
|
|
return new Hixie76\Frame;
|
|
}
|
|
|
|
public function frame($message) {
|
|
return chr(0) . $message . chr(255);
|
|
}
|
|
|
|
protected function _doStuffToObtainAnInt32($key) {
|
|
return preg_match_all('#[0-9]#', $key, $number) && preg_match_all('# #', $key, $space) ?
|
|
implode('', $number[0]) / count($space[0]) :
|
|
''
|
|
;
|
|
}
|
|
|
|
protected function _createHandshakeThingy($key1, $key2, $code) {
|
|
return md5(
|
|
pack('N', $this->_doStuffToObtainAnInt32($key1))
|
|
. pack('N', $this->_doStuffToObtainAnInt32($key2))
|
|
. $code
|
|
, true);
|
|
}
|
|
} |