检查请求的URL


9

使用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 );

注释掉条件之后,仍然发送响应。所以我想我使用了错误的钩子。
shanebp

您是否通过或类似方式检查了var $request$urlvar的外观var_dump,我发现检查输入和输出始终会得出正确的答案。
farinspace

2
引荐网址很容易被伪造,不能用于任何形式的安全性。
米洛

我们正在使用令牌和SSL。我们还想检查引用网址,而不管它是否可以被伪造。
shanebp

2
它是一个向网络开放的API,这与裁判身份验证和SSL无关。您可能还正在禁用CORS保护...除非只有登录的用户可以使用,否则它的安全性为零。
马克·卡普伦

Answers:


5

该筛选器绝对不是您要查找的筛选器。该过滤器将在返回结果之前触发,该结果WP_REST_Request::from_url()似乎是一种工厂方法,仅在内部用于处理嵌入。

更好的选择是WP_Errorrest_pre_dispatch过滤器上返回实例。

一些警告:

正如@milo所提到的,引荐来源网址不可靠,不应用于安全检查。

此外,不能保证设置。

对于这些问题,下面是一个示例,说明如何使用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 );

4

您从客户端收到的任何内容均被视为用户输入,因此不应被信任。由于标头易于操作和滥用,因此我建议不要使用此方法来获取敏感数据。

如果请求来自页面,则可以采用另一种方法。否则,任何人都可以从任何地方向API发送请求并更改引荐来源网址。

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

如果存在nounce且有效,则允许该请求。否则,将其阻止。


4
+1 ...这是一个API...。仅从浏览器获得调用的假设是荒谬的。
马克·卡普伦

是的,我认为nounce是更好的方法,因为如果有人直接向API发送请求,则nounce不存在。
杰克·约翰逊

4

@ssnepenthe的aswer说的很对,您使用的钩子不是传入请求中的正确对象。

请求信息可立即用于PHP,因此您可以使用最早的钩子来检查它们。而且,如果要在请求API的上下文中执行此操作,则应使用REST API请求的最早钩子。@ssnepenthe'rest_pre_dispatch'提出的建议很好,也许另一个选择是允许您在出现问题时返回错误。rest_authentication_errors

但是杰克·约翰森Jack Johansson说的对,HTTP标头(例如@ssnepenthe的aswer中使用的引用标头)是不可信的,因为它们很容易被客户端更改。因此,这就像在门前放一个保安,谁会问“可以安全进入?” 对任何想进去的人:那是行不通的。

但是解决方案提出了杰克·约翰逊的答案(随机数)也不是一个真正的解决方案:随机数的全部要点是随时间变化,而公共API终结点不能具有随时间变化的事物。此外,WP nonce仅在有登录用户的情况下才是可信任的(对于公共API可能不是这种情况,并且如果用户已登录,则可能没有理由检查传入域:您信任用户,而不是信任用户)。用户机器。

那么该怎么办?

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

通常,所有以$_SERVER键开头的值HTTP_都以标头开头,并且必须将其视为不安全的用户输入

但是,例如,$_SERVER['REMOTE_ADDR']包含用于与服务器的TCP连接的IP地址,这意味着它可信任的1

这也意味着:

  • 正确配置服务器以生成该$_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']))。

但是有一个问题

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

在这种情况下,原始请求IP通常以形式提供$_SERVER['HTTP_X_FORWARDED_FOR'],但$_SERVERHTTP_它开头的那些值之一实际上并不可信。

因此,如果您的网络服务器位于反向代理服务器2的后面,即使对于反向$_SERVER['REMOTE_ADDR']防护2来说也没有用,并且基于域的白名单只能在代理服务器级别实现。

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


笔记

1好吧,从理论上讲,如果有人入侵了您的ISP或攻击者从您的LAN内部进行攻击,这可能会被破坏,在这两种情况下,您都几乎无济于事。

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


OP正在尝试获取引荐来源网址,因此我假设他想在页面上执行引荐,而不直接对API进行ping操作。
杰克·约翰逊

@JackJohansson实际上是OP从未提及的引用者:)他们说他们想“检查它是否来自'允许的'URL”,这听起来像他们希望将SPepicic域的API端点列入白名单,而且OP中的代码段也提供了相同的功能我的主意。
gmazzap
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.