я настроил нормальный CSRF и т. д. и работал бы хорошо, но потом, когда я пойду и использую ajax, используя API-интерфейс whatwg-fetch (https://github.com/github/fetch)
Теперь все кажется в порядке, и все работает хорошо, что у меня есть. НО! Затем я добавляю настройки CSRF, как показано ниже, и все время происходит сбой:
Итак, я использовал нормальный, но он терпит неудачу, и в заголовке я получаю сообщение: Failed CSRF check!
$app->add(new \Slim\Csrf\Guard);
Но я хотел добавить собственное сообщение и т. Д., Поэтому добавил следующее, но все равно оно не проходит.
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setFailureCallable(function ($request, $response, $next) {
$request = $request->withAttribute("csrf_status", false);
return $next($request, $response);
});
return $guard;
};
$app->add($container->get('csrf'));
Затем в моем классе я проверяю это:
if (false === $req->getAttribute('csrf_status')) {...}else{//all ok}
Но что бы ни случилось, оно всегда терпит неудачу.
в моем JS я добавляю детали токена к запросу, как:
fetch('/post/url',{
method: 'POST',
headers: {
'X-CSRF-Token': {
'csrf_name':csrf_name,
'csrf_value':csrf_value
}
},
body: new FormData(theForm)
Я посмотрел в опубликованных данных и т. д., и данные формы представлены в том числе значения CSRF и т. д. Так что данные CSRF требуется отправлять через форму, а также заголовок?
Итак, как мне настроить Ajax для работы с Slim CSRF, чего мне не хватает?
заранее спасибо
Я также не смог достать, чтобы положить токены в тело. Я решил расширить класс, чтобы я мог изменить метод __invoke. Я добавил некоторый код, чтобы извлечь csrf из заголовков.
в ваших зависимостях теперь используйте этот класс.
$c['csrf'] = function ($c) {
return new \Foo\CSRF\Guard;
};
Расширенный класс.
<?php
namespace MYOWN\CSRF;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* CSRF protection middleware.
*/
class Guard extends \Slim\Csrf\Guard
{
public function __construct(
$prefix = 'csrf',
&$storage = null,
callable $failureCallable = null,
$storageLimit = 200,
$strength = 16,
$persistentTokenMode = false
) {
parent::__construct(
$prefix,
$storage,
$failureCallable,
$storageLimit,
$strength,
$persistentTokenMode);
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$this->validateStorage();
// Validate POST, PUT, DELETE, PATCH requests
if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$body = $request->getParsedBody();
$body = $body ? (array)$body : [];
$name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
$value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
if (!empty($csrfTokens = $request->getHeader('x-csrf-token'))) {
$csrfTokens = json_decode($csrfTokens[0], true);
$name = isset($csrfTokens[$this->prefix . '_name']) ? $csrfTokens[$this->prefix . '_name'] : false;
$value = isset($csrfTokens[$this->prefix . '_value']) ? $csrfTokens[$this->prefix . '_value'] : false;
}
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$request = $this->generateNewToken($request);
$failureCallable = $this->getFailureCallable();
return $failureCallable($request, $response, $next);
}
}
// Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
$request = $this->generateNewToken($request);
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $next($request, $response);
}}
хорошо после нескольких попыток за последний день и сужая его до fetch api
Я решил вернуться к доверенным методам jQuery aJax, и это, похоже, сработало.
Кажется следующее body
и new FormData()
не было подобрано:
fetch('/post/url',{
method: 'POST',
body: new FormData(theForm)
Так что выключил это для
$.ajax({
url : '/url/to/post',
type: "POST",
data: {key:value, kay:value}
И все работало хорошо.
Следующая проблема, которую следует рассмотреть, — это обновление ключей при первом вызове ajax, что предотвращает повторные вызовы, если страница не обновляется, но это на другой день.
Я еще раз попробовал это после прочтения одного из блогов одного из создателей. Так что вы можете игнорировать мой предыдущий ответ.
Отправка csrf в теле с этими заголовками проходит проверку csrf.
const data = {
'csrf_name': csrf_name,
'csrf_value': csrf_value,
};
fetch(apiUrl, {
method: 'POST',
credentials: 'include',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded; charset=utf-8',
},
}).then((response) => {
if (response.ok) {
return response.json();
}
return null;
}).then((json) => {
console.log(json);
}).catch(() => {
});
Что в итоге помогло мне добиться успеха с Slim PHP и значениями CSRF при использовании fetch добавлял credentials: 'include'
на запрос о получении, например:
const body = JSON.stringify({
csrf_name: csrfName.value,
csrf_value: csrfValue.value
// You can add more data here
});
fetch('/some/request', {
method: 'POST',
body: body,
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
}).then(...)