공개적으로 WordPress REST API v2 엔드 포인트 숨기기


15

내가 사용을 시작하고자하는 워드 프레스의 REST API v2가 내 사이트에서 쿼리 정보. 엔드 포인트 URL을 직접 방문하면 모든 데이터를 공개적으로 볼 수 있습니다. 또한 많은 자습서에서 라이브 사이트가 아닌 테스트 또는 로컬 서버 사용에 대해 언급하고 있습니다.

내 질문은 :

  • 이것은 생산 현장에서 사용하기위한 것입니까?
  • /wp-json/wp/v2/users/사이트에 등록 된 모든 사용자를 보여주는 사람과 같이 엔드 포인트를 볼 수있게하는 보안 위험이 있습니까?
  • 인증 된 사용자 만 엔드 포인트에 액세스하도록 허용 할 수 있습니까?

보안과 관련된 모범 사례를 따르고 있으므로 모든 팁이 도움이 될 것입니다. API 문서는 인증을 언급,하지만 난 직접 액세스되는 URL을 방지하는 방법을 모르겠어요. 다른 사람들은 일반적으로 너무 많은 정보를 노출시키지 않고 외부 응용 프로그램에서이 데이터에 액세스하도록 어떻게 설정합니까?


1
실제 질문은 엔드 포인트 클라이언트 측 (예 : AJAX 호출) 또는 서버 측 (아마도 다른 애플리케이션의)을 사용하고 있습니까?
TheDeadMedic

1
참고 : 최신 버전의 WordFence 플러그인에는 '/? author = N'스캔, oEmbed API 및 WordPress REST API를 통한 사용자 이름 검색 방지 옵션
squarecandy

답변:


18

이것은 생산 현장에서 사용하기위한 것입니까?

예. 많은 사이트에서 이미 사용하고 있습니다.

사이트에 등록 된 모든 사용자를 표시하는 / 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() ) );
}

다른 사람들은 일반적으로 너무 많은 정보를 노출시키지 않고 외부 응용 프로그램에서이 데이터에 액세스하도록 어떻게 설정합니까?

정보 가 무엇인지 / 언제 모르기 때문에이 질문에 대답하기가 어렵습니다 . 그러나 우리는 모두 참조치트 시트를 사용 하고 있습니다.


1
중요 사항 : "노출은 REST API를 통해 노출되도록 설정된 게시물 유형을 작성한 사용자로 제한됩니다." -모든 고객에게 사용자가있는 온라인 상점 인 경우이 사용자는을 통해 노출되지 않습니다 /wp-json/wp/v2/users/. (참조 wordpress.stackexchange.com/q/252328/41488 @JHoffmann 의견)
squarecandy

'X-WP-Nonce'헤더에 REST 기반 nonce wp_create_nonce ( 'wp_rest')가 필요하거나이 중 어느 것도 작동하지 않으며 항상 403을 리턴합니다.
Andrew Killen

5

인증 된 사용자 만 엔드 포인트에 액세스하도록 허용 할 수 있습니까?

컨텐츠를 보려면 인증이 필요한 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를 사용하는 방법에 따라 클라이언트 인증에 대해 자세히 알아야 할 수도 있습니다.

그런 다음 다음 인수를 추가하여 REST API 지원으로 사용자 정의 게시물 유형을 등록 할 수 있습니다. 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 );
}

당신은 볼 수 있습니다 rest_controller_class사용하는 My_Private_Posts_Controller대신 기본 컨트롤러를.

설명서 외부에서 REST API를 사용하는 데 대한 좋은 예와 설명을 찾기가 어려웠습니다 . 기본 컨트롤러 확장에 대한 훌륭한 설명을 찾았 으며 여기 에 엔드 포인트 추가에 대한 철저한 안내서가 있습니다.


2

로그인하지 않은 모든 사용자가 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으로 죽는 것이 좋습니다.
Mark Kaplun

@MarkKaplun-예, 당신은 그것에 대해 정확합니다. 나는 본질적으로 공개 데이터를 전혀 제공하지 않는 사이트의 맥락에서 이것을 사용하고 있으며 사용자, 사용자 메타, 사용자 정의 게시물 유형 데이터 등을 포함하여 우리가 저장하는 데이터는 대중이 절대 액세스해서는 안되는 독점 데이터입니다 . 클래식 WP 템플릿 구조 내에서 많은 작업을 수행하면 특정 데이터를 비공개로 유지하고 REST API를 통해 공개적으로 액세스 할 수 있음을 갑자기 깨닫게됩니다. 어쨌든, 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
이것이 왜 OP의 질문에 대답하는지 텍스트로 자세히 설명해 주시겠습니까?
kero

이것은 op의 대답이 아니며 실제로 실제로 작업하는 방법을 보여주는 코드 만 제공했으며 프로그래밍 방식으로 쉽게 이해할 수 있도록 노력했습니다
dipen patel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.