Ẩn các điểm cuối WordPress REST API v2 khỏi chế độ xem công khai


14

Tôi muốn bắt đầu sử dụng WordPress REST API v2 để truy vấn thông tin từ trang web của mình. Tôi nhận thấy rằng khi tôi truy cập URL điểm cuối trực tiếp, tôi có thể thấy tất cả dữ liệu công khai. Tôi cũng đã thấy rằng rất nhiều hướng dẫn đề cập đến việc sử dụng máy chủ thử nghiệm hoặc máy chủ cục bộ hơn là các trang web trực tiếp.

Câu hỏi của tôi là:

  • Điều này có nghĩa là được sử dụng trên các trang web trong sản xuất?
  • Có bất kỳ rủi ro bảo mật nào khi cho phép mọi người xem các điểm cuối, chẳng hạn như /wp-json/wp/v2/users/hiển thị tất cả người dùng đã đăng ký vào trang web không?
  • Có thể chỉ cho phép người dùng được ủy quyền truy cập điểm cuối không?

Tôi muốn đảm bảo rằng tôi đang tuân theo các thực tiễn tốt nhất về bảo mật, vì vậy mọi mẹo đều hữu ích. Các tài liệu api đề cập đến xác thực, nhưng tôi không chắc làm thế nào để ngăn URL truy cập trực tiếp. Làm thế nào để những người khác thường thiết lập dữ liệu này được truy cập bởi các ứng dụng bên ngoài mà không để lộ quá nhiều thông tin?


1
Câu hỏi thực sự là, bạn đang sử dụng phía máy khách điểm cuối (tức là trong các cuộc gọi AJAX) hay phía máy chủ (có lẽ từ một ứng dụng khác)?
TheDeadMote

1
Lưu ý: Phiên bản mới nhất của plugin WordFence có tùy chọn "Ngăn chặn việc phát hiện tên người dùng thông qua '/? Tác giả = N' quét, API oEmbed và API WordPress REST"
squarecandy

Câu trả lời:


18

Điều này có nghĩa là được sử dụng trên các trang web trong sản xuất?

Đúng. Nhiều trang web đã được sử dụng nó .

Có bất kỳ rủi ro bảo mật nào khi cho phép mọi người xem các điểm cuối, chẳng hạn như / wp-json / wp / v2 / users / hiển thị tất cả người dùng đã đăng ký vào trang web không?

Không. Phản hồi của máy chủ không liên quan gì đến bảo mật, bạn có thể làm gì với quyền truy cập màn hình trống / chỉ đọc? Không có gì!

Tuy nhiên, nếu trang web của bạn cho phép mật khẩu yếu, có một số vấn đề . Nhưng đó là chính sách của trang web của bạn, API REST không biết gì về điều đó.

Có thể chỉ cho phép người dùng được ủy quyền truy cập điểm cuối không?

Đúng. Bạn có thể làm điều đó bằng cách sử dụng gọi lại quyền .

Ví dụ:

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() ) );
}

Làm thế nào để những người khác thường thiết lập dữ liệu này được truy cập bởi các ứng dụng bên ngoài mà không để lộ quá nhiều thông tin?

Câu hỏi này rất khó trả lời vì chúng ta không biết những gì / khi có quá nhiều thông tin . Nhưng tất cả chúng ta đều sử dụng tài liệu tham khảocheatheets .


1
Điều quan trọng cần lưu ý: "Phơi sáng bị giới hạn ở những người dùng đã tạo ra các loại bài đăng được thiết lập để được hiển thị thông qua API REST." - vì vậy nếu bạn nói, một cửa hàng trực tuyến nơi mọi khách hàng có một người dùng, những người dùng này không được tiếp xúc qua /wp-json/wp/v2/users/. (Tham khảo wordpress.stackexchange.com/q/252328/41488 @JHoffmann bình luận)
squarecandy

Cần lưu ý rằng bạn cần phải có một nonp wp_create_nonce ('wp_rest') dựa trên REST trong tiêu đề 'X-WP-Nonce', hoặc không có thứ gì trong số này sẽ hoạt động cả, và sẽ luôn trả về 403.
Andrew Killen

5

Có thể chỉ cho phép người dùng được ủy quyền truy cập điểm cuối không?

Có thể thêm một cuộc gọi lại quyền tùy chỉnh vào điểm cuối API của bạn yêu cầu xác thực để xem nội dung. Người dùng trái phép sẽ nhận được phản hồi lỗi"code": "rest_forbidden"

Cách đơn giản nhất để làm điều này là mở rộng WP_REST_Posts_Controll. Đây là một ví dụ rất đơn giản về điều đó:

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' );
  }

}

Bạn sẽ nhận thấy rằng các cuộc gọi lại quyền function get_items_permissions_checksử dụng current_user_canđể xác định xem có cho phép truy cập hay không. Tùy thuộc vào cách bạn đang sử dụng API, bạn có thể cần tìm hiểu thêm về xác thực ứng dụng khách.

Sau đó, bạn có thể đăng ký loại bài đăng tùy chỉnh của mình với hỗ trợ API REST bằng cách thêm các đối số sau vào register_post_type

  /**
   * 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 );
}

Bạn sẽ thấy rest_controller_classsử dụng My_Private_Posts_Controllerthay vì bộ điều khiển mặc định.

Tôi đã gặp khó khăn khi tìm các ví dụ và giải thích tốt cho việc sử dụng API REST ngoài tài liệu . Tôi đã tìm thấy lời giải thích tuyệt vời này về việc mở rộng bộ điều khiển mặc định và đây là một hướng dẫn rất kỹ lưỡng để thêm các điểm cuối .


2

Đây là những gì tôi đã sử dụng để chặn tất cả người dùng chưa đăng nhập sử dụng API REST:

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);
    }
}

Khi việc sử dụng điểm cuối còn lại sẽ mở rộng, loại chiến lược này sẽ trở thành vấn đề. Cuối cùng, điểm cuối wp-json sẽ thay thế quản trị viên ajax, nghĩa là cũng sẽ có tất cả các loại yêu cầu giao diện người dùng hợp pháp. Dù sao, tốt hơn là chết với 403 hơn là một cái gì đó có thể được hiểu là nội dung.
Đánh dấu Kaplun

@MarkKaplun - vâng, bạn đúng về điều đó. Tôi đang sử dụng điều này trong ngữ cảnh của một trang web về cơ bản không có dữ liệu công khai nào và dữ liệu chúng tôi đang lưu trữ bao gồm người dùng, meta người dùng, dữ liệu loại bài đăng tùy chỉnh, v.v. là dữ liệu độc quyền không được truy cập bởi công chúng . Thật hấp dẫn khi bạn thực hiện một loạt công việc trong cấu trúc mẫu WP cổ điển để đảm bảo dữ liệu nhất định là riêng tư và sau đó nhận ra rằng tất cả đều có thể truy cập công khai thông qua API REST. Dù sao, điểm tốt về việc phục vụ 403 ...
squarecandy

0
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 );

1
Bạn có thể giải thích bằng văn bản tại sao và làm thế nào điều này trả lời các câu hỏi của OP không?
kero

Đây không phải là câu trả lời của op và tôi chỉ đưa ra mã để chỉ ra cách làm việc thực tế và tôi đã cố gắng để bạn có thể dễ dàng hiểu được bằng lập trình Nếu bạn hiểu nó
nhúng patel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.