check the requesting url

时间:2017-10-04 作者:shanebp

使用WP 4.8.2

使用rest api处理请求时,检查请求URL的最佳方法是什么?

例如,一个站点收到一个请求,您想检查它是否来自“允许的”URL。如果不允许URL,则失败。

这不起作用:

function my_check_request_url( $request, $url ) {

    $bits = parse_url( $url );

    if ( $bits[\'host\'] != \'example.com\' )
       $request = false;

    return $request;

}
add_filter( \'rest_request_from_url\', \'my_check_request_url\', 10, 2 );

3 个回复
最合适的回答,由SO网友:ssnepenthe 整理而成

那个过滤器肯定不是你要找的那个。该筛选器在返回的结果之前激发WP_REST_Request::from_url() 这似乎是一种工厂方法,仅在内部用于处理嵌入。

更好的选择是返回WP_Error 上的实例rest_pre_dispatch filter.

一些注意事项:

正如@milo所提到的,referer不可靠,不应用于安全检查。

此外,不保证设置。

下面是一个示例,说明如何使用rest_pre_dispatch 如果请求来自错误的引用,则筛选以导致请求失败:

function wpse281916_rest_check_referer( $result, $server, $request ) {
    if ( null !== $result ) {
        // Core starts with a null value.
        // If it is no longer null, another callback has claimed this request.
        // Up to you how to handle - for this example we will just return early.
        return $result;
    }

    $referer = $request->get_header( \'referer\' );

    if ( ! $referer ) {
        // Referer header is not set - If referer is required, return a WP_Error instance instead.
        return $result;
    }

    $host = wp_parse_url( $referer, PHP_URL_HOST );

    if ( ! $host ) {
        // Referer is malformed - If referer is required, return a WP_Error instance instead.
        return $result;
    }

    if ( \'mysite.com\' !== $host ) {
        // Referer is set to something that we don\'t allow.
        return new WP_Error(
            \'invalid-referer\',
            \'Requests must contain a valid referer\',
            compact( \'referer\' )
        );
    }

    // Otherwise we are good - return original result and let WordPress handle as usual.
    return $result;
}
add_filter( \'rest_pre_dispatch\', \'wpse281916_rest_check_referer\', 10, 3 );

SO网友:Johansson

您从客户端收到的任何内容都被视为用户输入,不应被信任。由于标题很容易被操纵和滥用,如果您依赖它来处理敏感数据,我的建议是不要使用此方法。

如果请求来自某个页面,您可以使用另一种方法。否则,任何人都可以从任何地方向API发送请求并更改引用者。

假设您有一堆页面被过滤为“允许”。您只能为这些页面创建一个名词,然后在请求中验证它们。

如果一个名词存在且有效,则允许该请求。否则,请阻止它。

SO网友:gmazzap

@ssnepenthe\'s aswer 正确的说法是,您使用的钩子不是传入请求中的正确钩子。

PHP可以立即获得请求信息,因此您可以使用可用的最早挂钩来检查它们。如果要在请求API的上下文中执行此操作,则应该使用REST API请求的最早挂钩。\'rest_pre_dispatch\' 根据建议,猪笼草很好,可能还有另一种选择rest_authentication_errors 这将允许您在出现问题时返回错误。

但是Jack Johansson 就在这里saying HTTP头(就像@ssnepenthe的aswer中使用的referer头)是不可信的,因为客户端很容易更改它们。所以,这就像在门前放一个保安,他只会问“让你进去安全吗?”对任何想进去的人来说:那是行不通的。

但是JackJohansson提出的解决方案(nonce)也不是一个真正的解决方案:nonce的全部要点是随着时间的变化而变化,而公共API端点不能有随时间变化的东西。此外,只有当有登录用户时,WP nonce才是可信的,这可能不是公共API的情况,如果用户登录,可能没有理由检查传入的域:您信任用户,而不是用户计算机。

So, what to do?

好吧,即使HTTP头是不可信任的,也不是所有可用的信息$_SERVER 来自标题。

通常,所有$_SERVER 键以开头的值HTTP_ 来自标题,必须视为不安全的用户输入。

但是,例如,$_SERVER[\'REMOTE_ADDR\'] 包含用于TCP连接到服务器的IP地址,这意味着is 可信赖的。

这也意味着:

正确配置服务器以生成$_SERVER[\'REMOTE_HOST\'] 值(例如,在Apache中,您需要HostnameLookups On 在您的httpd.conf) 该值使用gethostbyaddr 执行反向DNS查找以解析存储在中的IP的域名$_SERVER[\'REMOTE_ADDR\']您可以获得一个非常可靠的主机名,用于对照白名单进行检查(对于代码,您可以修改@ssnepenthe的aswer中的代码,在那里您可以替换$referer = $request->get_header(\'referer\') 具有$referer = gethostbyaddr($_SERVER[\'REMOTE_ADDR\'])).

但是有一个issue.

如果您的Web服务器位于反向代理(实际上是非常常见的解决方案)之后,那么到Web服务器的TCP连接实际上是由代理建立的,所以$_SERVER[\'REMOTE_ADDR\'] 将是代理的IP,而不是最初发送请求的客户端的IP。

在这种情况下,原始请求IP通常可用为$_SERVER[\'HTTP_X_FORWARDED_FOR\'], 但作为其中之一$_SERVER 以开头的值HTTP_ 这真的不可信。

因此,如果您的Web服务器位于反向代理之后$_SERVER[\'REMOTE_ADDR\'] 对于这样的守卫来说是没有用的,基于域的白名单只能在代理级别实现。

简而言之,API端点安全的可靠解决方案应该使用一些真正的身份验证机制(例如oAuth)来实现,或者应该直接在服务器配置上而不是在应用程序级别上实现。

理论上,如果有人入侵了您的ISP或攻击者从您的局域网内进行攻击,那么它可能会被破坏,在这两种情况下,您几乎无法保证安全。

如果您不知道自己是否支持反向代理,可以从本地PC发送请求,并检查$_SERVER[\'REMOTE_ADDR\'] 在服务器上匹配本地PC IP,如果$_SERVER[\'HTTP_X_FORWARDED_FOR\'] 存在,并且与本地PC IP匹配。

结束

相关推荐

Php致命错误:无法将WP_REST_RESPONSE类型的对象用作wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php中

我向WordPress添加了一个自定义端点,如下所示: add_action( \'rest_api_init\', function () { register_rest_route( \'menc/v1\', \'/crosscat/(?P[\\w-]+)/(?P[\\w-]+)\', array( \'methods\' => \'GET\', \'callback\' => \'dept_cat_api\',&#x