如何从 Javascript 设置 WebSocket Origin Header?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30144233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set WebSocket Origin Header from Javascript?
提问by Miles
I'm trying to use javascript to make a websocket request from a local test.dev
page to a server running at ip 123.123.123.123
on behalf of test.com
. The request goes through, but the 123.123.123.123
server sees the Origin: test.dev
header in the websocket request and rejects the connection because it wants to see Origin: test.com
.
我正在尝试使用 javascript 从本地test.dev
页面向在 ip123.123.123.123
上运行的服务器发出 websocket 请求test.com
。请求通过了,但是123.123.123.123
服务器看到了Origin: test.dev
websocket 请求中的标头并拒绝连接,因为它想看到Origin: test.com
.
Here is the javascript code for connecting the socket:
这是连接套接字的javascript代码:
ws = new WebSocket("123.123.123.123");
ws = new WebSocket("123.123.123.123");
How can I use javascript to start a websocket connection with a dishonest Origin
header of Origin: test.com
?
如何使用 javascript 启动带有不诚实Origin
标头的websocket 连接Origin: test.com
?
I was hoping something like this would work, but I can't find any such:
我希望这样的事情会奏效,但我找不到任何这样的:
ws = new WebSocket("123.123.123.123", "test.com");
ws = new WebSocket("123.123.123.123", "test.com");
回答by Martin Konecny
The simple solution would be to simply create an entry in your hosts
file to map test.com
to 123.123.123.123
. You would need to remove this entry later when you want to connect the "real" test.com
.
简单的解决方案是简单地在hosts
文件中创建一个条目以映射test.com
到123.123.123.123
. 当您想连接“真实”时,您需要稍后删除此条目test.com
。
A less hacky solution would require the use of a proxy which can re-write your headers for you on-the-fly. Consider install nginx
on your system, and then proxing the request to 123.123.123.123
keeping everything the same exceptfor the Origin header. Here's the entry you would need in your nginx config file:
一个不那么笨拙的解决方案需要使用代理,它可以为您即时重写您的标头。考虑nginx
在您的系统上安装,然后代理请求以123.123.123.123
保持除Origin 标头之外的所有内容相同。这是您在 nginx 配置文件中需要的条目:
server {
server_name test.dev;
location / {
proxy_pass http://123.123.123.123;
proxy_set_header Origin test.com;
# the following 3 are required to proxy WebSocket connections.
# See more here: http://nginx.com/blog/websocket-nginx/
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
回答by Andy E
How can I use javascript to start a websocket connection with a dishonest
Origin
header ofOrigin: test.com
?
如何使用 javascript 启动带有不诚实
Origin
标头的websocket 连接Origin: test.com
?
If we could forge the origin of requests in JavaScript, the same origin policy wouldn't be very good at keeping us safe. It exists solely to protect us from this and other potential attack vectors.
如果我们可以在 JavaScript 中伪造请求的来源,那么同源策略就不能很好地保证我们的安全。它的存在仅仅是为了保护我们免受这种和其他潜在的攻击媒介的侵害。
As this looks like dev work, have you considered using a web debugging proxy such as Fiddler(free) or Charles(paid)? With those you could modify the initial handshake request or response for the WebSocket for your own machine or any test machines that are proxied through the debugger.
由于这看起来像是开发工作,您是否考虑过使用诸如Fiddler(免费)或Charles(付费)之类的 Web 调试代理?通过这些,您可以修改您自己的机器或通过调试器代理的任何测试机器的 WebSocket 的初始握手请求或响应。
回答by Labo
A good solution is to override the WebSocket call with another websocket library, like https://github.com/websockets/ws. To use this node.js library in a browser, you just have to use http://browserify.org/.
一个好的解决方案是使用另一个 websocket 库覆盖 WebSocket 调用,例如https://github.com/websockets/ws。要在浏览器中使用这个 node.js 库,你只需要使用http://browserify.org/。
回答by Gautam Sharma
If you reallymust forge a fake 'origin' header value from javascript - there is a way. Its not something you will find in your generally accepted principles handbook, but here it is:
如果您真的必须从 javascript 伪造一个假的“原点”标头值 - 有一种方法。你不会在普遍接受的原则手册中找到它,但它是:
Create a php file that invokes the socket, with a fake origin value. Now call the php file using ajax, from you javascript.
创建一个调用套接字的 php 文件,并使用假的原始值。现在使用 ajax 调用 php 文件,来自您的 javascript。
It may not be elegant, ethical or acceptable, but never accept anyone telling you that it cant be done.
它可能不优雅、不道德或不可接受,但永远不要接受任何人告诉你它无法完成。
'send.php' was called using ajax from javascript
'send.php' 是在 javascript 中使用 ajax 调用的
send.php contents
send.php 内容
require "websocket_client.php";
$client = new Client("IP_ADDR:PORT", $_GET[mobile] ."|".$_GET[login]);
$client->send('1112223333|sms');
$client->send(json_encode(array('login'=>$user,'msg'=>$msg)));
echo $client->receive();`enter code here`
websocket_client.php was a class file with basic websocket functions (including the custom origin values
websocket_client.php 是一个具有基本 websocket 功能的类文件(包括自定义源值
/**
* Perform WebSocket handshake
*/
protected function connect() {
$url_parts = parse_url($this->socket_uri);
$scheme = $url_parts['scheme'];
$host = $url_parts['host'];
$user = isset($url_parts['user']) ? $url_parts['user'] : '';
$pass = isset($url_parts['pass']) ? $url_parts['pass'] : '';
$port = isset($url_parts['port']) ? $url_parts['port'] : ($scheme === 'wss' ? 443 : 80);
$path = isset($url_parts['path']) ? $url_parts['path'] : '/';
$query = isset($url_parts['query']) ? $url_parts['query'] : '';
$fragment = isset($url_parts['fragment']) ? $url_parts['fragment'] : '';
$path_with_query = $path;
if (!empty($query)) $path_with_query .= '?' . $query;
if (!empty($fragment)) $path_with_query .= '#' . $fragment;
if (!in_array($scheme, array('ws', 'wss'))) {
throw new BadUriException(
"Url should have scheme ws or wss, not '$scheme' from URI '$this->socket_uri' ."
);
}
$host_uri = ($scheme === 'wss' ? 'ssl' : 'tcp') . '://' . $host;
// Open the socket. @ is there to supress warning that we will catch in check below instead.
$this->socket = @fsockopen($host_uri, $port, $errno, $errstr, $this->options['timeout']);
if ($this->socket === false) {
throw new ConnectionException(
"Could not open socket to \"$host:$port\": $errstr ($errno)."
);
}
// Set timeout on the stream as well.
stream_set_timeout($this->socket, $this->options['timeout']);
// Generate the WebSocket key.
$key = self::generateKey();
// Default headers (using lowercase for simpler array_merge below).
$headers = array(
'host' => $host . ":" . $port,
'user-agent' => 'websocket-client-php',
'connection' => 'Upgrade',
'upgrade' => 'websocket',
'origin' => $MY_CUSTOM_SHADY_VALUE,
'sec-websocket-key' => $key,
'sec-websocket-version' => '13',
);
// Handle basic authentication.
if ($user || $pass) {
$headers['authorization'] = 'Basic ' . base64_encode($user . ':' . $pass) . "\r\n";
}
// Deprecated way of adding origin (use headers instead).
if (isset($this->options['origin'])) $headers['origin'] = $this->options['origin'];
// Add and override with headers from options.
if (isset($this->options['headers'])) {
$headers = array_merge($headers, array_change_key_case($this->options['headers']));
}
$header =
"GET " . $path_with_query . " HTTP/1.1\r\n"
. implode(
"\r\n", array_map(
function($key, $value) { return "$key: $value"; }, array_keys($headers), $headers
)
)
. "\r\n\r\n";
// Send headers.
$this->write($header);
// Get server response.
$response = '';
do {
$buffer = stream_get_line($this->socket, 1024, "\r\n");
$response .= $buffer . "\n";
$metadata = stream_get_meta_data($this->socket);
} while (!feof($this->socket) && $metadata['unread_bytes'] > 0);
/// @todo Handle version switching
// Validate response.
if (!preg_match('#Sec-WebSocket-Accept:\s(.*)$#mUi', $response, $matches)) {
$address = $scheme . '://' . $host . $path_with_query;
throw new ConnectionException(
"Connection to '{$address}' failed: Server sent invalid upgrade response:\n"
. $response
);
}
$keyAccept = trim($matches[1]);
$expectedResonse
= base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
if ($keyAccept !== $expectedResonse) {
throw new ConnectionException('Server sent bad upgrade response.');
}
$this->is_connected = true;
}
}