6

我正在使用https://github.com/lemmingzshadow/php-websocket/

我可以允许一些域,并且我已经允许localhost了一个指向我的本地服务器的域。但我想知道在他的计算机上有服务器的其他人是否可以使用他的本地主机服务器中的脚本连接到我的 websocket(通过我的域)。

以下是相关代码:

-> 服务器/server.php

$server->setAllowedOrigin('localhost');
$server->setAllowedOrigin('mydomain.com');

-> 服务器/lib/WebSocket/Connection.php

// check origin:
if($this->server->getCheckOrigin() === true)
{
    $origin = (isset($headers['Sec-WebSocket-Origin'])) ? $headers['Sec-WebSocket-Origin'] : false;
    $origin = (isset($headers['Origin'])) ? $headers['Origin'] : $origin;
    if($origin === false)
    {
        $this->log('No origin provided.');
        $this->sendHttpResponse(401);
        stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
        $this->server->removeClientOnError($this);
        return false;
    }

    if(empty($origin))
    {
        $this->log('Empty origin provided.');
        $this->sendHttpResponse(401);
        stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
        $this->server->removeClientOnError($this);
        return false;
    }

    if($this->server->checkOrigin($origin) === false)
    {
        $this->log('Invalid origin provided.');
        $this->sendHttpResponse(401);
        stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
        $this->server->removeClientOnError($this);
        return false;
    }
}

-> 服务器/lib/WebSocket/Server.php

public function checkOrigin($domain)
{
    $domain = str_replace('http://', '', $domain);
    $domain = str_replace('https://', '', $domain);
    $domain = str_replace('www.', '', $domain);
    $domain = str_replace('/', '', $domain);

    return isset($this->_allowedOrigins[$domain]);
}

public function setAllowedOrigin($domain)
{
    $domain = str_replace('http://', '', $domain);
    $domain = str_replace('www.', '', $domain);
    $domain = (strpos($domain, '/') !== false) ? substr($domain, 0, strpos($domain, '/')) : $domain;
    if(empty($domain))
    {
        return false;
    }
    $this->_allowedOrigins[$domain] = true;     
    return true;
}

编辑:

也许我不够清楚。我希望每个人都可以连接到 websocket,但前提是他们在我的域(或我的本地主机)中,比如 AJAX 中的同源策略。

我担心的是,如果我允许本地主机,也许其他计算机中的所有其他本地主机也将被允许。

4

3 回答 3

1

如果你想确定,你应该添加一个 IP 检查,分析$_SERVER["REMOTE_ADDR"]. 正在检查的来源是客户端提供的文本值,可以很容易地伪造。

if (!in_array($_SERVER["REMOTE_ADDR"], array("127.0.0.1", "ip.of.dom.ain")) exit;

如果您不想对 IP 地址进行硬编码或者频繁更改,您可以使用gethostbyname来获取域的 IP 地址,如下所示。请注意,当必须为域查询 DNS 时,这将增加每个请求的延迟,并且当您的 DNS 出现故障时,这种方式将导致超时。(当然可以优化以下代码)

$allowed_origins = array('localhost', 'mydomain.com');
$allowed_ips = array();
foreach ($allowed_origins as $domain) {
    $server->setAllowedOrigin($domain);
    $allowed_ips[] = gethostbyname($domain);
}
if (!in_array($_SERVER["REMOTE_ADDR"], $allowed_ips)) exit; 

执行此操作的正确方法可能是通过您的 Web 服务器保护您的资源,以便它只接受来自您希望允许的 IP 地址的请求(请参阅Apache中的拒绝或nginx中的拒绝)。

于 2012-12-30T14:49:22.427 回答
1

虽然当我只想允许我的本地主机时,我担心允许来自所有本地主机的连接,但我发现在另一个问题中,卡纳卡说:

澄清一下,在不妥协且表现良好的浏览器中运行的 Javascript 不会影响 Sec-WebSocket-Origin 的值,该值保存页面加载的原始站点的值(允许您的服务器仅允许某些起始点)。但是,如果您在 Node.js 中作为 WebSocket 客户端运行 Javascript,它可以将原始值设置为任何它想要的值。CORS 安全性是为了浏览器用户的安全,而不是为了您的服务器。您需要其他机制来保护您的服务器。

然后,我的起源检查代码根本不安全;并且是否都允许所有本地主机都没有关系,因为如果有人有足够的知识使用他自己的本地主机连接到我的 websocket,那么他很可能可以修改 Origin 标头。

于 2013-01-01T23:46:45.340 回答
0

如果您正在检查Origin标头,则足以强制执行诸如同源策略之类的内容。标Origin头可以在自定义应用程序(如节点 WebSocket 客户端)中在浏览器之外被欺骗,但这没关系,对于普通的 HTTP 请求来说是一样的。SOP 仅与浏览器有关。

所以检查Origin标头不是关于访问保护,而是关于 CSRF 保护。如果用户当前已登录,则不允许不受信任的第三方站点连接到您的 WebSocket 端点(自动发送凭据)。

于 2015-07-02T07:06:49.697 回答