WordPress REST API v2エンドポイントをパブリックビューから隠す


14

私が使用を開始したいと思いますワードプレスの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ベースのナンスのwp_create_nonce(「wp_rest」)を持っている必要があります、またはこのようなものはどれもまったく動作しませんし、常に403を返すことに注意すべきである
アンドリュー・キレン

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で死ぬ方が良いです。
マークカプルン

@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の質問にどのように、またどのように答えるかをテキストで詳しく説明していただけますか
ケロ

これはOPの答えではないと私は実質的にどのように仕事に表示するコードのみを与え、私はあなたがそれを理解した場合はプログラムから簡単に理解を取得するためにあなたにしようとした
dipenパテル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.