私のサイトから情報を検索するには WordPress REST API v2 を使い始めたいです。エンドポイントのURLに直接アクセスすると、すべてのデータを一般に公開できることに気付きました。また、ライブサイトではなくテストサーバーまたはローカルサーバーの使用について多くのチュートリアルが言及していることもわかりました。
私の質問は:
/wp-json/wp/v2/users/
のように、エンドポイントを誰にでも見られるようにすることに対するセキュリティ上のリスクはありますか?セキュリティに関するベストプラクティスに従っていることを確認したいので、ヒントがあれば役立つでしょう。 api docs は認証について言及していますが、URLに直接アクセスされないようにする方法がわかりません。他人はどのように通常あまりに多くの情報を公開せずに外部のアプリケーションによってアクセスされるためにこのデータを設定しますか?
これは生産現場での使用を意図していますか?
はい! 多くのサイトがすでにそれを使っています 。
サイトに登録されているすべてのユーザーを表示する/ 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() ) );
}
他人はどのように通常あまりに多くの情報を公開せずに外部のアプリケーションによってアクセスされるためにこのデータを設定しますか?
情報が多すぎるがいつどのような場合かわからないため、この質問に答えるのは困難です。しかし、私たちはみんな references および cheatsheets を使っています。
許可されたユーザーのみにエンドポイントへのアクセスを許可することは可能ですか?
コンテンツを表示するには認証が必要なカスタムエンドポイントコールバックを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
を使っています。
documentation の外でREST APIを使用するための良い例や説明を見つけるのは困難です。私はこのすばらしい デフォルトコントローラを拡張することについての説明 を見つけました、そしてここに エンドポイントを追加するための非常に徹底的なガイド .
これは、ログインしていないすべてのユーザーが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);
}
}
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 );