WordPress как на ладони
rgbcode is looking for WordPress developers.

Пароли приложений (авторизация)

В WordPress 5.6 введена новая система создания авторизованных запросов к разным API WordPress, в частности к REST API. Эта система называется — Application Passwords (пароли приложений).

Если говорить просто, то пароли приложений нужны для того, чтобы дать возможность приложению авторизоваться как пользователь сайта (с теми же правами), но при этом не давать сам пароль от аккаунта. Пароль создается в профиле отдельно и не храниться в чистом виде в базе данных (храниться он в виде хэша). Таких паролей можно создать сколько угодно много. Также любой из созданных паролей в любой момент может быть отозван (удален).

Существующая система аутентификации на основе файлов cookie никуда не удаляется, и все что работало на этой основе будет работать как и прежде.

Логика паролей приложений была взята из плагина Application Passwords, поэтому рекомендуется его деактивировать после обновления до WordPress 5.6. Впрочем, если его оставить активным, сайт все равно должен работать без ошибок. Этот плагин можно использовать для будущего прототипирования.

Формат Пароля приложения

Длина пароля указывается константой PW_LENGTH и составляет 24 символа. Создается он функцией wp_generate_password(), в которой отключено использование спец символов. Получается, пароль может состоять из символов: a-zA-Z0-9 - строчных, заглавных букв, чисел.

На выводе пароль делиться на фрагменты по 4 символа, например:

abcd EFGH 1234 ijkl MNOP 6789

Пароли приложений можно использовать как с пробелами, так и без них. Пробелы будут просто удалены до того, как пароль будет проверен. Вместо пробелов можно также использовать символы _ и -.

abcd EFGH 1234 ijkl MNOP 6789
abcd_EFGH_1234_ijkl_MNOP_6789
abcd-EFGH-1234-ijkl-MNOP-6789

Так пароли очищаются от лишних символов (пробелов, тире) перед сравнением:

/*
 * Strip out anything non-alphanumeric. This is so passwords can be used with
 * or without spaces to indicate the groupings for readability.
 *
 * Generated application passwords are exclusively alphanumeric.
 */
$password = preg_replace( '/[^a-z\d]/i', '', $password );

Выше мы описали варианты, которые WordPress поймёт. В своём Http клиенте используйте тот, который он поддерживает. Например, Postman поймёт все варианты, а PhpStorm поймёт все, кроме варианта с пробелами.

Хранение данных

Хэш пароля будет храниться в виде массива в метаполе пользователя _application_passwords, также как сейчас храниться сессия логина, см. WP_Session_Tokens.

Пример значения метаполя _application_passwords:

Array (
	[0] => Array (
			[uuid] => fbadcb50-4385-4701-96a6-9a4f07527d08
			[app_id] =>
			[name] => My Aplication
			[password] => $P$Bui9Czv.OEQ6ES6YYMWge8/e.qmWJP/
			[created] => 1607599946
			[last_used] =>
			[last_ip] =>
		)
)

Как видно, в данных есть уникальный ID пароля uuid, Название приложения, Дата создания пароля, данные последнего использования ключа.

Класс WP_Application_Passwords содержит все необходимые методы для сохранения и получения пароля.

Создание Пароля приложения

Есть 3 способа создать Пароль для приложения.

Способ 1: на странице профиля в админке WP

Данный блок доступен только если сайт работает по https.

Здесь же можно смотреть какие пароли используются и если нужно удалять пароли.

При авторизации с использованием конкретного пароля в таблице появится данные когда и кем он был использован. Это поля last_used и last_ip.

Данные в эти поля записываться один раз и обновятся через 24 часа при повторном использовании этого пароля. Это небольшая оптимизация производительности, чтобы не обновлять метаданные каждый раз при запросе.

Способ 2: специальная страница в админке /authorize-application.php

Этот способ создан для использования его самим приложением.

При обычном GET запросе на корневой REST маршрут /wp-json/ в ответе, в поле authentication содержаться данные о способах авторизации. С версии WP 5.6 там появилась авторизация application-passwords в которой указана ссылка, которую можно дать пользователю сайта. Пройдя по этой ссылке пользователь авторизует ваше приложение (создаст для него пароль по которому приложение сможет общаться с сайтом от имени пользователя).

{
	"name": "wptest.dev",
	"description": "Ещё один сайт на WordPress",
	"url": "http://example.com/wp",
	"home": "https://example.com",
	"namespaces": [
		"oembed/1.0",
		"wp/v2",
		"wp-site-health/v1"
	],
	"authentication": {
		"application-passwords": {
			"endpoints": {
				"authorization": "https://example.com/wp/wp-admin/authorize-application.php"
			}
		}
	},
	"routes": { ... }
}

Если такой ссылки нет, то скорее всего сайт не использует HTTPS протокол или эта возможность намерено отключена.

Значение JSON свойства response.authentication['application-passwords'].endpoints.authorization обычно выглядит так:

https://example.com/wp-admin/authorize-application.php

Пройдя по этой ссылке можно также как и выше создать очередной пароль приложения.

Однако, если вас на такую ссылку отправляет приложение, то в неё можно передать дополнительные GET параметры. Чтобы не нужно было вводить имя и ID приложения. Доступные GET параметры:

app_name(строка) (рекомендуется указать)
Название приложения, понятное для человека. Это имя станет именем созданного пароля (по нему вы сможете орриентироваться). Например: WordPress Mobile App on iPhone 12.
app_id(UUID) (рекомендуется указать)
Идентификатор приложения в формате UUID. Этот ID позволяет идентифицировать конкретное приложение. Особого значения у этого ID нет. Вы как разработчик можете использовать его для поиска всех паролей приложений, созданных для вашего приложения.
success_url(строка) (рекомендуется указать)

URL-адрес, на который перейдет пользователь после создания пароля. При этом указанный URL будут добавлены 3 дополнительных GET параметра: site_url, user_login, password. Эти данные нужно сохранить в приложении чтобы авторизоваться по API.

Если этот параметр не указан, то при клике на кнопку создания пароля, пользователя никуда не перенаправит, а ему будет показан созданный пароль. Его ему нужно будет ввести в приложение.

reject_url(строка)

URL, на который отправить пользователь при отказе от создания пароля.

Если не указано, то пользователя отправит на success_url с параметром ?success=false. Если не указан и success_url, то пользователя перенаправит в консоль.

Теперь рассмотрим на примере как это работает. Допустим мы получили следующую ссылку от приложения (для понятности перенес параметры на отдельные строки):

https://example.com/wp-admin/authorize-application.php
	?app_name=My Site On Android
	&app_id=d2321b5c-edf0-4a3c-9223-4719f8e6b028
	&success_url=https://example.com/auth-ok
	&reject_url=https://example.com/auth-error

Перейдем по ссылке:

Теперь при клике на «Да, я разрешаю...» будет создан пароль и пользователя перекинет на ссылку

https://example.com/auth-ok
	?site_url=https://example.com/wp
	&user_login=kama
	&password=GENERATED_PASS

Ничего страшного, если пользователю сначала нужно войти на сайт. Поскольку параметры передаются через GET переменные, все они попадут в параметр ?redirect=... и после авторизации на сайте пользователь сможет продолжить авторизацию приложения.

success_url и reject_url должны использовать https:// соединение или протоколы приложений myapp://, иначе юзер увидит такое сообщение.

Вот пример простого javascript-приложения (менее 100 строк кода), которое использует его для аутентификации на сайте WordPress. Это не самый аккуратный код, он был создан за пару часов, но в нём видно как нужно делать авторизованные запросы.

Способ 3: REST API

POST запрос на маршрут /wp/v2/users/{id}/application-passwords. Подробнее смотрите здесь.

Способ 4: Функция create_new_application_password()

См. WP_Application_Passwords::create_new_application_password()

Использование Пароля приложения

Пароль приложения не будет работать на странице wp-login.php. Он создан для программ, а не людей.

REST API

Пароль приложения может быть передан в REST запросе по https:// через Basic авторизацию.

Т.е. вам нужно передать в заголовках запроса параметр Authorization со значением Basic base64(login:app_password).

HTTP API авторизация через Пароль приложения

$response = wp_remote_request( 'http://example.com/wp-json/wp/v2/posts/113',
	[
		'method'    => 'DELETE',
		'headers'   => [
			'Authorization' => 'Basic ' . base64_encode( 'login:abcd_EFGH_1234_ijkl_MNOP_6789' )
		]
	]
);

if( 200 == wp_remote_retrieve_response_code( $response ) )
	echo 'Пост удален!';
else
	echo 'Ошибка: Не удалось удалить пост';

Смотрите также: WP HTTP API

JavaScript авторизация через Пароль приложения

Такая авторизация нужна только если отправляется AJAX запрос с одного сайта на другой. Если AJAX запрос происходит внутри сайта, и пользователь уже авторизован, то вместе с запросом будут отправлены куки аутентификации, а это значит что авторизация уже есть, нужно только указать nonce-код (см. выше).

Обратите внимание, что такой JS должен подключатся на страницах куда имеют доступ только админы иначе любой сможет открыть js файл и посмотреть логин и пароль.

$.ajax({
	url: 'http://example.com/wp-json/wp/v2/posts/113',
	method: 'DELETE',
	crossDomain: true,
	beforeSend: function ( xhr ) {
		xhr.setRequestHeader( 'Authorization', 'Basic ' + Base64.encode( 'login:abcd_EFGH_1234_ijkl_MNOP_6789' ) );
	},
	success: function( data, txtStatus, xhr ) {
		console.log( data );
		console.log( xhr.status );
	}
});

CLI авторизация через Пароль приложения

Обновим описание у пользователя 12

curl -X PUT -d "description=Описание юзера" --user "login:aaaa ssss d3d3 f4f4 g5g5 h6h6" https://example.com/wp-json/wp/v2/users/12 | json_pp

Удалим пост 12

curl -X DELETE --user "login:aaaa ssss d3d3 f4f4 g5g5 h6h6" https://example.com/wp-json/wp/v2/posts/12 | json_pp

| json_pp (JSON Pretty Print) нужно чтобы JSON ответ не был в одну строку.

XML-RPC API

Чтобы использовать пароль приложения XML-RPC API, вы можете просто использовать его вместо реального пароля учетной записи.

Пример запроса из командной строки. В нем вам нужно просто заменить логин, пароль и имя хоста:

curl -H 'Content-Type: text/xml' -d '<methodCall><methodName>wp.getUsers</methodName><params><param><value>1</value></param><param><value>USERNAME</value></param><param><value>PASSWORD</value></param></params></methodCall>' https://HOSTNAME/xmlrpc.php

Другие API

Аутентификацию через пароль приложения также можно будет применить к будущим API WordPress. Например, если GraphQL будет добавлен в WordPress, пароли приложений обеспечат ему устоявшуюся логику аутентификации, которая будет работать из коробки.

Пример проверки является ли текущий запрос запросом к какому либо API для WPGraphQL. Теперь WPGraphQL сможет принимать аутентифицированные запросы без дополнительных плагинов, используя только функционал паролей приложений.

Заметки

По умолчанию пароли приложений доступны всем пользователям на сайтах, обслуживаемых по протоколу SSL/HTTPS. Изменить доступ можно с помощью фильтров wp_is_application_passwords_available и wp_is_application_passwords_available_for_user.

Например, чтобы полностью отключить пароли приложений, добавьте такой код в functions.php:

add_filter( 'wp_is_application_passwords_available', '__return_false' );

Без SSL злоумышленник будет видеть пароль приложения в перехваченном запросе между вашим сайтом и приложением. Если такой риск вас устраивает, то можно полностью отключить проверку доступности паролей приложения.

add_filter( 'wp_is_application_passwords_available', '__return_true' );

При желании можно ограничить, какие пользователи на вашем сайте могут использовать функцию паролей приложений. Например, используйте следующий код, чтобы разрешить использование паролей приложений только для администраторов:

add_filter( 'wp_is_application_passwords_available_for_user', 'fix_app_password_availability', 10, 2 );

function fix_app_password_availability( $available, $user ){

	if ( ! user_can( $user, 'manage_options' ) ) {
		$available = false;
	}

	return $available;
}

Дальнейшее развитие

Область доступа

В будущих версиях предполагается включить возможность ограничения доступа для конкретного пароля. Пока предполагается расширять такой функционал через плагины, которые затем будут добавлены в ядро.

Более подходящие права

Сейчас паролями приложений пользователя может управлять любой пользователь, имеющий право edit_user. Возможность настроить это поведение с помощью нового набора более тонких возможностей запланирована на WP 5.7.

Двухфакторная аутентификация

Введенные пароли приложений устраняют препятствия для включения многофакторной аутентификации.

Ранее, при включении еще одного фактора аутентификации на странице входа wp-login.php. Не было возможности внедрить такую же авторизацию на устаревшую систему XML-RPC. И от этой функциональности пришлось бы отказаться. Но теперь, когда есть другой вариант использовать различные API, также появляется возможность развивать базовую авторизацию через wp-login.php.

Связанные функции

Все функции смотрите здесь.

wp_authenticate_application_password() Авторизует пользователя используя пароль приложения.
wp_is_application_passwords_available() Проверяет можно ли использовать Пароли приложений для текущего запроса.

--

Ссылки по теме:

16 комментариев
    Войти