web-dev-qa-db-fra.com

Cacher WordPress REST Points de terminaison API v2 à partir de l'affichage public

Je voudrais commencer à utiliser le WordPress REST API v2 pour interroger des informations sur mon site. J'ai remarqué que lorsque je visite directement une URL de point de terminaison, je peux voir toutes les données publiquement. J'ai également vu que de nombreux tutoriels mentionnent l'utilisation de serveurs de test ou de serveurs locaux plutôt que de sites en direct.

Mes questions sont:

  • Est-ce que cela est destiné à être utilisé sur des sites en production?
  • Existe-t-il un risque de sécurité pour permettre à quiconque de visualiser les points finaux, tel que /wp-json/wp/v2/users/, qui affiche tous les utilisateurs enregistrés sur le site?
  • Est-il possible d'autoriser uniquement les utilisateurs autorisés à accéder à un noeud final?

Je veux m'assurer que je respecte les meilleures pratiques en matière de sécurité, alors tout conseil serait utile. Les api docs mentionnent l'authentification, mais je ne sais pas comment empêcher l'accès direct à l'URL. Comment les autres utilisateurs configurent-ils généralement ces données pour qu'elles soient accessibles par des applications externes sans exposer trop d'informations?

11
Morgan

Est-ce que cela est destiné à être utilisé sur des sites en production?

Oui! _ { De nombreux sites l'ont déjà utilisé }.

Existe-t-il un risque de sécurité pour permettre à quiconque de visualiser les points d'extrémité, tel que/wp-json/wp/v2/users /, qui affiche tous les utilisateurs enregistrés sur le site?

Non! Les réponses du serveur n'ont rien à voir avec la sécurité. Que pouvez-vous faire avec un écran vide/un accès en lecture seule? Rien!

Cependant, si vos sites autorisent les mots de passe faibles, il y a certains problèmes } _. Mais c'est la politique de vos sites, REST API ne sait rien à ce sujet.

Est-il possible d'autoriser uniquement les utilisateurs autorisés à accéder à un noeud final?

Oui! Vous pouvez le faire en utilisant rappel d'autorisation .

Par exemple:

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

Comment les autres utilisateurs configurent-ils généralement ces données pour qu'elles soient accessibles par des applications externes sans exposer trop d'informations?

Il est difficile de répondre à cette question car nous ne savons pas quoi/quand est trop d’informations . Mais nous utilisons tous références et feuilles de mise en garde .

16
MinhTri

Est-il possible d'autoriser uniquement les utilisateurs autorisés à accéder à un noeud final?

Il est possible d'ajouter un rappel d'autorisation personnalisé à votre point de terminaison API, ce qui nécessite une authentification pour afficher le contenu. Les utilisateurs non autorisés recevront une réponse d'erreur "code": "rest_forbidden"

Le moyen le plus simple consiste à étendre WP_REST_Posts_Controller. Voici un exemple très simple de cela:

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

}

Vous remarquerez que le rappel d'autorisations function get_items_permissions_check utilise current_user_can pour déterminer s'il faut autoriser l'accès. En fonction de votre utilisation de l'API, vous devrez peut-être en savoir plus sur l'authentification du client.

Vous pouvez ensuite enregistrer votre type de publication personnalisé auprès de REST API en ajoutant les arguments suivants dans 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 );
}

Vous verrez que rest_controller_class utilise My_Private_Posts_Controller au lieu du contrôleur par défaut.

J'ai eu du mal à trouver de bons exemples et explications pour utiliser l'API REST en dehors de documentation . J'ai trouvé cet excellent explication de l'extension du contrôleur par défaut , et voici un guide très complet sur l'ajout de points de terminaison .

5
Dalton

Voici ce que j'ai utilisé pour empêcher tous les utilisateurs non connectés d'utiliser l'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);
    }
}
1
squarecandy
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 );
0
dipen patel