WordPress 4.7.1 REST API expune în continuare utilizatorii
Am actualizat WordPress-ul la versiunea 4.7.1
și după aceea am încercat să enumăr utilizatorii prin REST API, care ar fi trebuit să fie rezolvat, dar am putut să recuperez în continuare utilizatorii.
https://mywebsite.com/wp-json/wp/v2/users
Rezultat:
[{"id":1,"name":"admin","url":"","description":"","link":"https:\/\/mywebsite\/author\/admin\/","slug":"admin","avatar_urls":{"24": ...
Changelog-ul din ultima versiune:
REST API-ul expunea date despre utilizatori pentru toți utilizatorii care au fost autori ai unei postări de tip public. WordPress 4.7.1 limitează acest lucru doar la tipurile de postări care au specificat că ar trebui să fie afișate în REST API. Raportat de Krogsgard și Chris Jean.
După instalarea plugin-ului Disable REST API
, pare că totul funcționează bine, dar nu-mi place să folosesc plugin-uri pentru fiecare lucru minor.
Rezultatul după utilizarea plugin-ului este:
{"code":"rest_cannot_access","message":"Doar utilizatorii autentificați pot accesa REST API.","data":{"status":401}}
Cum pot rezolva această problemă fără a folosi plugin-ul, sau de ce există în continuare după actualizare?
EDITARE 30.9.2017
Am realizat că există un conflict între plugin-ul contact 7
și Disable REST API
care va genera eroarea 401 unauthorized
.
Când încerci să trimiți un mesaj prin formularul contact 7
, acesta va face o cerere
wp-json/contact-form-7/v1/contact-forms/258/feedback
și dezactivarea acestuia nu este o idee bună.

Acest fragment de cod va ascunde rezultatele pentru endpoint-urile de utilizatori, articole și comentarii și va returna eroarea 404, în timp ce restul apelurilor API vor continua să funcționeze normal.
::ACTUALIZARE::
add_filter('rest_endpoints', function(){
$toRemove = ['users', 'posts', 'comments'];
foreach($toRemove as $val)
{
if (isset($endpoints['/wp/v2/'.$val])) {
unset($endpoints['/wp/v2/'.$val]);
}
if(isset($endpoints['/wp/v2/'.$val.'/(?P<id>[\d]+)'])) {
unset($endpoints['/wp/v2/'.$val.'/(?P<id>[\d]+)']);
}
}
return $endpoints;
});
::ACTUALIZARE::
Acest fragment va elimina toate endpoint-urile implicite.
<?php remove_action('rest_api_init', 'create_initial_rest_routes', 99); ?>

Unde se adaugă acest cod personalizat? Nu menționați unde ar trebui salvat acest lucru.

Această soluție dezactivează toate operațiunile CRUD pe utilizatori, consultați această implementare doar pentru cererile GET: https://github.com/szepeviktor/wordpress-fail2ban/commit/98eb4f292a5a6bdae637f9410eb7bb9d6dffd81c

Cum pot dezactiva mydomain.com/wp-json/ pentru a nu mai afișa toate aceste date în format json?

Această soluție este incompatibilă cu Gutenberg, care aruncă:
Uncaught (in promise) Response { type: "basic", url: "/wp-json/wp/v2/users/?who=authors&per_page=100&_locale=user", redirected: false, status: 404, ok: false, statusText: "Not Found", headers: Headers, body: ReadableStream, bodyUsed: false }
Ar fi mai bine să forțăm autentificarea pe aceste endpoint-uri.

/**
* Învelește un callback implicit existent transmis ca parametru și creează
* un nou callback de permisiune introducând verificări preliminare și
* revenind la callback-ul implicit în caz de succes.
*/
function permission_callback_hardener ($existing_callback) {
return function ($request) use($existing_callback) {
if (! current_user_can('list_users')) {
return new WP_Error(
'rest_user_cannot_view',
__( 'Ne pare rău, nu aveți permisiunea de a accesa utilizatorii.' ),
[ 'status' => rest_authorization_required_code() ]
);
}
return $existing_callback($request);
};
}
function api_users_endpoint_force_auth($endpoints)
{
$users_get_route = &$endpoints['/wp/v2/users'][0];
$users_get_route['permission_callback'] = permission_callback_hardener($users_get_route['permission_callback']);
$user_get_route = &$endpoints['/wp/v2/users/(?P<id>[\d]+)'][0];
$user_get_route['permission_callback'] = permission_callback_hardener($user_get_route['permission_callback']);
return $endpoints;
}
add_filter('rest_endpoints', 'api_users_endpoint_force_auth');
- Endpoint-urile nu sunt blocate pentru administratori (Gutenberg continuă să funcționeze)
- Endpoint-ul respinge utilizatorii anonimi într-un mod corespunzător.
- Este suficient de generic pentru a suporta endpoint-uri viitoare.
current_user_can
ar putea fi îmbunătățit, făcut mai generic.- Se presupune că metoda
GET
este prima pentru o rută înregistrată (ceea ce până acum a fost întotdeauna adevărat)

Eliminați link-ul API din head-ul HTML dacă doriți.
// https://wordpress.stackexchange.com/a/211469/77054
// https://wordpress.stackexchange.com/a/212472
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
Apoi solicitați autentificare pentru toate cererile.
// Puteți solicita autentificare pentru toate cererile REST API prin adăugarea unei verificări is_user_logged_in la filtrul rest_authentication_errors.
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error( 'rest_not_logged_in', 'Doar utilizatorii autentificați pot accesa REST API.', array( 'status' => 401 ) );
}
return $result;
});
Aceasta vă va lăsa cu mesajul dorit.
Pentru a opri enumerarea, puteți folosi ceva de genul acesta.
// https://perishablepress.com/stop-user-enumeration-wordpress/
// blochează scanările de enumerare WP
// https://m0n.co/enum
if (!is_admin()) {
// format URL implicit
if (preg_match('/author=([0-9]*)/i', $_SERVER['QUERY_STRING'])) die();
add_filter('redirect_canonical', 'shapeSpace_check_enum', 10, 2);
}
function shapeSpace_check_enum($redirect, $request) {
// format URL permalink
if (preg_match('/\?author=([0-9]*)(\/*)/i', $request)) die();
else return $redirect;
}
Consultați întregul articol pentru alte tehnici avansate.

Cod .htaccess pentru a bloca toate scanările autorilor
# Început blocare scanări autori
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (author=\d+) [NC]
RewriteRule .* - [F]
# Sfârșit blocare scanări autori
Puteți elimina acest cod prin funcție așa cum sugerează răspunsul acceptat

Am folosit acest mic cod în fișierul functions.php:
/**
* Acces API REST doar pentru administratori
*
* @return void
*/
function api_rest_only_for_admin_users() {
$current_user = wp_get_current_user();
if ( in_array('administrator', $current_user->roles ) ) {
return;
} else {
wp_die('Ne pare rău, nu aveți permisiunea să accesați aceste date','API REST Interzis',403);
}
}
add_filter( 'rest_api_init', 'api_rest_only_for_admin_users', 99 );

Pentru a completa răspunsul lui BlueSuiter din 2017, iată o soluție pentru a filtra utilizatorii după rol, care face soluția compatibilă cu editorul Gutenberg.
add_filter( 'rest_endpoints', function( $endpoints ) {
if(is_user_logged_in()) {
$user = wp_get_current_user();
$roles = array('editor', 'administrator', 'author');
if( array_intersect($roles, $user->roles ) ) return $endpoints;
}
if ( isset( $endpoints['/wp/v2/users'] ) ) unset( $endpoints['/wp/v2/users'] );
if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
return $endpoints;
});
Editorul Gutenberg trebuie să interogheze API-ul REST pentru a obține autorul. Prin urmare, este necesar să permitem accesul pentru toate rolurile de utilizator de pe site-ul tău care au acces la editorul Gutenberg, fără a uita de postările personalizate.
Pe endpoint-ul public al API-ului REST, se va returna o eroare 404 deoarece is_user_logged_in va returna întotdeauna false.

Dacă utilizați un firewall pentru a proteja site-ul WordPress, cea mai bună opțiune este să blocați punctul final (endpoint) API care expune detaliile utilizatorilor prin intermediul firewall-ului.
Detectați URL-ul https://example.com/wp-json/wp/v2/users
și pur și simplu blocați-l din firewall.
Editare: blocați doar punctul final specific pentru detaliile utilizatorilor și nu întregul API REST.

// Bloc API JSON WP pentru utilizatori
function disable_custom_rest_endpoints( $endpoints ) {
$routes = array( '/wp/v2/users', '/wp/v2/users/(?P<id>[\d]+)' );
foreach ( $routes as $route ) {
if ( empty( $endpoints[ $route ] ) ) {
continue;
}
foreach ( $endpoints[ $route ] as $i => $handlers ) {
if ( is_array( $handlers ) && isset( $handlers['methods'] ) &&
'GET' === $handlers['methods'] ) {
unset( $endpoints[ $route ][ $i ] );
}
}
}
return $endpoints;
}
add_filter( 'rest_endpoints', 'disable_custom_rest_endpoints' );

Am creat un plugin complet care funcționează pentru acest lucru în GITHUB.
https://github.com/MRKWP/mrkwp-rest-permissions/
Ceea ce am făcut a fost să mă asigur că folosesc INIT pentru începutul acțiunii, acest lucru asigură că funcțiile pluggable funcționează conform așteptărilor.
De asemenea, folosesc capacitatea WordPress 'Edit_posts' pentru API. Acest lucru asigură că administratorul și editorul de blocuri funcționează corect.
Aruncă o privire la acel plugin pentru a rezolva orice probleme CVE-2017-5487 ridicate de auditorii de securitate.
De asemenea, folosește PHP CS, astfel încât va funcționa cu o instalare VIP sau cu ceva care necesită implementarea standardelor.
Sper că acest lucru ajută pe cineva. Mi-a luat ceva timp să fac asta să funcționeze corect pe propriile mele site-uri și servere.

Privind pe scurt codul, numele „hardener” este un pic înșelător, deoarece nu întărește endpoint-urile, ci le face să respingă întotdeauna cererile - pur și simplu îl instalezi condiționat. De asemenea, apelezi funcții de activare și dezactivare care nu există. Dar da, se pare că asta ar face treaba.

Pentru a putea remedia această problemă, mai întâi trebuie să cunoști sursa ei.
- Folosești pluginuri SEO precum: All in one SEO pack sau Yoast? Încearcă să le dezactivezi și verifică din nou.
- Folosești pluginul Jetpack? Încearcă să-l dezactivezi și verifică din nou.
Te rog să-mi spui dacă aceste sugestii te-au îndreptat în direcția corectă.
O metodă rapidă de a rezolva această problemă este să blochezi URL-ul menționat mai jos în fișierul tău .htaccess. https://mywebsite.com/wp-json/wp/v2/users
