add anywhere csrf protection
This commit is contained in:
parent
c55264cf42
commit
24ea8deeec
|
|
@ -1,7 +1,7 @@
|
||||||
{# app/Views/macros/forms.twig #}
|
{# app/Views/macros/forms.twig #}
|
||||||
{% macro form_open(action, attributes = '') %}
|
{% macro form_open(action, attributes = '') %}
|
||||||
<form action="{{ action }}" method="post" {{ attributes|raw }}>
|
{# Добавляем data-ajax="true" для автоматической CSRF защиты #}
|
||||||
{# Выводим глобальную переменную csrf_token #}
|
<form action="{{ action }}" method="post" data-ajax="true" {{ attributes|raw }}>
|
||||||
{{ csrf_field()|raw }}
|
{{ csrf_field()|raw }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Форма принятия/отклонения #}
|
{# Форма принятия/отклонения #}
|
||||||
<form action="/invitation/accept/{{ token }}" method="POST">
|
<form action="/invitation/accept/{{ token }}" method="POST" data-ajax="true">
|
||||||
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>">
|
{{ csrf_field()|raw }}
|
||||||
<input type="hidden" name="action" value="accept">
|
<input type="hidden" name="action" value="accept">
|
||||||
|
|
||||||
<div class="d-flex gap-3">
|
<div class="d-flex gap-3">
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Форма регистрации #}
|
{# Форма регистрации #}
|
||||||
<form action="/invitation/complete/{{ token }}" method="POST">
|
<form action="/invitation/complete/{{ token }}" method="POST" data-ajax="true">
|
||||||
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>">
|
{{ csrf_field()|raw }}
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="completeName" class="form-label">Ваше имя</label>
|
<label for="completeName" class="form-label">Ваше имя</label>
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="inviteUserForm" action="/organizations/users/{{ organization_id }}/invite" method="POST">
|
<form id="inviteUserForm" action="/organizations/users/{{ organization_id }}/invite" method="POST" data-ajax="true">
|
||||||
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>">
|
{{ csrf_field()|raw }}
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="inviteEmail" class="form-label">Email адрес</label>
|
<label for="inviteEmail" class="form-label">Email адрес</label>
|
||||||
|
|
|
||||||
|
|
@ -94,3 +94,97 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
document.cookie = cookieString;
|
document.cookie = cookieString;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получение CSRF токена из мета-тега
|
||||||
|
*/
|
||||||
|
function getCsrfToken() {
|
||||||
|
const meta = document.querySelector('meta[name="csrf-token"]');
|
||||||
|
return meta ? meta.getAttribute('content') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обновление CSRF токена в мета-теге
|
||||||
|
*/
|
||||||
|
function updateCsrfToken(token, hash) {
|
||||||
|
const tokenMeta = document.querySelector('meta[name="csrf-token"]');
|
||||||
|
const hashMeta = document.querySelector('meta[name="csrf-hash"]');
|
||||||
|
if (tokenMeta) tokenMeta.setAttribute('content', token);
|
||||||
|
if (hashMeta) hashMeta.setAttribute('content', hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перехват fetch()
|
||||||
|
const originalFetch = window.fetch;
|
||||||
|
window.fetch = function(url, options = {}) {
|
||||||
|
// Добавляем CSRF токен в заголовки
|
||||||
|
if (!options.headers) {
|
||||||
|
options.headers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если headers это объект - добавляем токен
|
||||||
|
if (options.headers instanceof Headers) {
|
||||||
|
options.headers.set('X-CSRF-TOKEN', getCsrfToken());
|
||||||
|
} else if (typeof options.headers === 'object') {
|
||||||
|
options.headers['X-CSRF-TOKEN'] = getCsrfToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Выполняем запрос
|
||||||
|
return originalFetch(url, options).then(response => {
|
||||||
|
// Проверяем, пришёл ли новый токен в ответе
|
||||||
|
const newToken = response.headers.get('X-CSRF-TOKEN');
|
||||||
|
const newHash = response.headers.get('X-CSRF-HASH');
|
||||||
|
if (newToken && newHash) {
|
||||||
|
updateCsrfToken(newToken, newHash);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Перехват XMLHttpRequest (для jQuery и других библиотек)
|
||||||
|
const originalOpen = XMLHttpRequest.prototype.open;
|
||||||
|
XMLHttpRequest.prototype.open = function(method, url) {
|
||||||
|
this._csrfToken = getCsrfToken();
|
||||||
|
return originalOpen.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
const originalSend = XMLHttpRequest.prototype.send;
|
||||||
|
XMLHttpRequest.prototype.send = function(body) {
|
||||||
|
// Добавляем CSRF токен в заголовки
|
||||||
|
this.setRequestHeader('X-CSRF-TOKEN', this._csrfToken || getCsrfToken());
|
||||||
|
|
||||||
|
// Слушаем ответ для обновления токена
|
||||||
|
this.addEventListener('load', function() {
|
||||||
|
const newToken = this.getResponseHeader('X-CSRF-TOKEN');
|
||||||
|
const newHash = this.getResponseHeader('X-CSRF-HASH');
|
||||||
|
if (newToken && newHash) {
|
||||||
|
updateCsrfToken(newToken, newHash);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return originalSend.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Автоматическое обновление CSRF токена в AJAX формах перед отправкой
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
const form = e.target;
|
||||||
|
if (form.dataset.ajax === 'true') {
|
||||||
|
const tokenInput = form.querySelector('input[name="csrf_token"]');
|
||||||
|
if (tokenInput) {
|
||||||
|
tokenInput.value = getCsrfToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обновление CSRF токена в скрытых полях при загрузке страницы (только для AJAX форм)
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const forms = document.querySelectorAll('form[data-ajax="true"]');
|
||||||
|
forms.forEach(function(form) {
|
||||||
|
const tokenInput = form.querySelector('input[name="csrf_token"]');
|
||||||
|
if (tokenInput) {
|
||||||
|
tokenInput.value = getCsrfToken();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
Loading…
Reference in New Issue