我想开始使用WordPress REST API v2从我的网站查询信息。我注意到,当我直接访问终结点URL时,可以公开看到所有数据。我也看到很多教程都提到使用测试服务器或本地服务器,而不是现场站点。

我的问题是:是否可以在生产环境中使用?
是否存在安全性
风险,允许任何人查看端点,例如
/wp-json/wp/v2/users/,它显示在该站点注册的所有用户?
是否可以只允许授权用户访问端点?

我想确保我遵循有关安全性的最佳实践,因此任何提示都将有所帮助。 api文档提到身份验证,但是我不确定如何防止直接访问URL。其他人通常如何设置此数据以供外部应用程序访问而不暴露太多信息?

评论

真正的问题是,您是使用端点客户端(即在AJAX调用中)还是服务器端(也许是来自其他应用程序)?

注意:WordFence插件的最新版本具有一个选项“通过'/?author = N'扫描,oEmbed API和WordPress REST API防止发现用户名”

#1 楼


是否打算在生产现场使用?


是的。许多站点已经在使用它。


是否存在允许所有人查看端点的安全风险,例如/ wp-json / wp / v2 / users /,其中显示了所有内容。用户注册到该网站?


否。服务器的响应与安全性无关,对于黑屏/只读访问该怎么办?什么都没有!

但是,如果您的站点允许使用弱密码,则存在一些问题。但这是您网站的政策,REST API对此一无所知。


是否可以仅允许授权用户访问端点?


是的。您可以使用权限回调来做到这一点。

例如:

if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) {
    return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you cannot view this resource with edit context.' ), array( 'status' => rest_authorization_required_code() ) );
}



其他人通常如何将这些数据设置为可以被外部应用程序访问而不会暴露太多信息?


这个问题很难回答,因为我们不知道什么/什么时候有太多信息。但是我们都在使用参考和备忘单。

评论


需要注意的重要事项:“曝光仅限于创作了帖子类型且设置为通过REST API公开的用户。” -因此,如果您说的是每个客户都有用户的在线商店,则不会通过/ wp-json / wp / v2 / users /公开这些用户。 (参考wordpress.stackexchange.com/q/252328/41488 @JHoffmann评论)

– squarecandy
17年10月10日在16:48

应当注意,您需要在“ X-WP-Nonce”标头中具有基于REST的随机数wp_create_nonce('wp_rest'),否则这些东西都将无法正常工作,并且始终返回403。

–安德鲁·基伦(Andrew Killen)
18/12/12在9:17

#2 楼


是否可以仅允许授权用户访问端点?


可以向您的API端点添加自定义权限回调,该回调需要身份验证才能查看内容。未经授权的用户将收到错误响应"code": "rest_forbidden"

最简单的方法是扩展WP_REST_Posts_Controller。这是一个非常简单的示例:

class My_Private_Posts_Controller extends WP_REST_Posts_Controller {

   /**
   * The namespace.
   *
   * @var string
   */
   protected $namespace;

   /**
   * The post type for the current object.
   *
   * @var string
   */
   protected $post_type;

   /**
   * Rest base for the current object.
   *
   * @var string
   */
   protected $rest_base;

  /**
   * Register the routes for the objects of the controller.
   * Nearly the same as WP_REST_Posts_Controller::register_routes(), but with a 
   * custom permission callback.
   */
  public function register_routes() {
    register_rest_route( $this->namespace, '/' . $this->rest_base, array(
        array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_items' ),
            'permission_callback' => array( $this, 'get_items_permissions_check' ),
            'args'                => $this->get_collection_params(),
            'show_in_index'       => true,
        ),
        array(
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => array( $this, 'create_item' ),
            'permission_callback' => array( $this, 'create_item_permissions_check' ),
            'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
            'show_in_index'       => true,
        ),
        'schema' => array( $this, 'get_public_item_schema' ),
    ) );

    register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
        array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_item' ),
            'permission_callback' => array( $this, 'get_item_permissions_check' ),
            'args'                => array(
                'context' => $this->get_context_param( array( 'default' => 'view' ) ),
            ),
            'show_in_index'       => true,
        ),
        array(
            'methods'             => WP_REST_Server::EDITABLE,
            'callback'            => array( $this, 'update_item' ),
            'permission_callback' => array( $this, 'update_item_permissions_check' ),
            'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
            'show_in_index'       => true,
        ),
        array(
            'methods'             => WP_REST_Server::DELETABLE,
            'callback'            => array( $this, 'delete_item' ),
            'permission_callback' => array( $this, 'delete_item_permissions_check' ),
            'args'                => array(
                'force' => array(
                    'default'     => true,
                    'description' => __( 'Whether to bypass trash and force deletion.' ),
                ),
            ),
            'show_in_index'       => false,
        ),
        'schema' => array( $this, 'get_public_item_schema' ),
    ) );     
  }

  /**
   * Check if a given request has access to get items
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function get_items_permissions_check( $request ) {
    return current_user_can( 'edit_posts' );
  }

}


您会注意到,权限回调function get_items_permissions_check使用current_user_can来确定是否允许访问。根据您使用API​​的方式,您可能需要了解有关客户端身份验证的更多信息。

然后可以在register_post_type中添加以下参数,从而在REST API支持下注册自定义帖子类型。

  /**
   * Register a book post type, with REST API support
   *
   * Based on example at: http://codex.wordpress.org/Function_Reference/register_post_type
   */
  add_action( 'init', 'my_book_cpt' );
  function my_book_cpt() {
    $labels = array(
        'name'               => _x( 'Books', 'post type general name', 'your-plugin-textdomain' ),
        'singular_name'      => _x( 'Book', 'post type singular name', 'your-plugin-textdomain' ),
        'menu_name'          => _x( 'Books', 'admin menu', 'your-plugin-textdomain' ),
        'name_admin_bar'     => _x( 'Book', 'add new on admin bar', 'your-plugin-textdomain' ),
        'add_new'            => _x( 'Add New', 'book', 'your-plugin-textdomain' ),
        'add_new_item'       => __( 'Add New Book', 'your-plugin-textdomain' ),
        'new_item'           => __( 'New Book', 'your-plugin-textdomain' ),
        'edit_item'          => __( 'Edit Book', 'your-plugin-textdomain' ),
        'view_item'          => __( 'View Book', 'your-plugin-textdomain' ),
        'all_items'          => __( 'All Books', 'your-plugin-textdomain' ),
        'search_items'       => __( 'Search Books', 'your-plugin-textdomain' ),
        'parent_item_colon'  => __( 'Parent Books:', 'your-plugin-textdomain' ),
        'not_found'          => __( 'No books found.', 'your-plugin-textdomain' ),
        'not_found_in_trash' => __( 'No books found in Trash.', 'your-plugin-textdomain' )
    );

    $args = array(
        'labels'             => $labels,
        'description'        => __( 'Description.', 'your-plugin-textdomain' ),
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'book' ),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => null,
        'show_in_rest'       => true,
        'rest_base'          => 'books-api',
        'rest_controller_class' => 'My_Private_Posts_Controller',
        'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )
    );

    register_post_type( 'book', $args );
}


您将看到rest_controller_class的用法My_Private_Posts_Controller而不是默认控制器。

我发现很难找到文档外使用REST API的良好示例和说明。我确实找到了扩展默认控制器的很好的解释,这是添加端点的非常详尽的指南。

评论


谢谢您,很好地满足了我的需求-尽管如果使用名称空间,请不要忘记在控制器类中包含名称空间-因为如果找不到控制器类,则不会出错(是的,我忘记了!)

–艾伦·富勒(Alan Fuller)
20年6月4日在14:06

#3 楼

这就是我用来阻止所有未登录用户完全不使用REST API的原因:

add_filter( 'rest_api_init', 'rest_only_for_authorized_users', 99 );
function rest_only_for_authorized_users($wp_rest_server){
    if ( !is_user_logged_in() ) {
        wp_die('sorry you are not allowed to access this data','cheatin eh?',403);
    }
}


评论


随着剩余端点的使用不断扩大,这种策略将成为问题。最后,wp-json端点将替换admin-ajax端点,这意味着还将存在各种合法的前端请求。无论如何,死于403可能比解释为内容更好。

–马克·卡普伦
17年12月1日在5:22



@MarkKaplun-是的,您是正确的。我是在一个根本不提供公共数据的网站的上下文中使用此信息,而我们存储的数据(包括用户,用户元数据,自定义帖子类型数据等)是专有数据,公众永远都不应访问。当您在经典的WP模板结构中进行大量工作以确保某些数据是私有的,然后突然意识到它们都可以通过REST API公开访问时,它会很糟糕。无论如何,服务403的好处是...

– squarecandy
17年12月1日下午14:29

#4 楼

add_filter( 'rest_api_init', 'rest_only_for_authorized_users', 99 );
function rest_only_for_authorized_users($wp_rest_server)
{
if( !is_user_logged_in() ) 

    wp_die('sorry you are not allowed to access this data','Require Authentication',403);
} } 
function json_authenticate_handler( $user ) {

global $wp_json_basic_auth_error;

$wp_json_basic_auth_error = null;

// Don't authenticate twice
if ( ! empty( $user ) ) {
    return $user;
}

if ( !isset( $_SERVER['PHP_AUTH_USER'] ) ) {
    return $user;
}

$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];


remove_filter( 'determine_current_user', 'json_authenticate_handler', 20 );

$user = wp_authenticate( $username, $password );

add_filter( 'determine_current_user', 'json_authenticate_handler', 20 );

if ( is_wp_error( $user ) ) {
    $wp_json_basic_auth_error = $user;
    return null;
}

$wp_json_basic_auth_error = true;

return $user->ID;}add_filter( 'determine_current_user', 'json_authenticate_handler', 20 );


评论


您能否在文字中详细说明为什么以及如何回答OP的问题?

– kero
18年1月8日在12:32

这不是op的答案,我只给出了代码来展示如何实际工作,并且我尝试过以编程方式让您容易理解。

–迪彭·帕特尔
18年1月9日在13:17



#5 楼

最佳选择是禁用V5新编辑器,然后禁用API json,如此处所述。

https://codber.com/2020/05/01/how-to-disable-wordpress-rest-在没有插件的情况下未登录到用户的api /

评论


仅链接的答案将随着过期的链接而过时。您可以根据答案的要点编辑答案,然后可以链接以获取更多详细信息。 :)

– Mayeenul伊斯兰教
20-05-10在18:56