Честно говоря, это просто вызывает слишком много хлопот в v1.0, чтобы иметь функциональность, которая требует трех представлений формы, с данными сеанса $_SESSION
содержащими все промежуточные вещи – только для того, чтобы пользователь начал операцию, затем откройте вторую вкладку и выполнить вторую операцию, которая попирает данные сеанса.
Я сомневаюсь, что это злонамеренно (но не может его удержать). Более вероятно, что пользователь запустит операцию, прервется, забыл, что они начали или не могут найти исходную вкладку, так что она начинается снова (затем позже находит исходную вкладку и пытается завершить операцию второй раз).
Поскольку я кодирую в PHP, я могу обнаружить наличие данных сеанса при отправке формы (как бы это сделать с JS, если пользователь так же, как открывает другую вкладку – я думаю, что мне нужен Ajax – правильно?).
Поэтому каждый раз, когда я запускаю операцию, я проверяю флаг в данных сеанса, и если он установлен, я перезагружаюсь в «Мне жаль, Дэйв. Я боюсь, что не могу сделать эту страницу, иначе я установил флаг и продолжаю (помню, чтобы очистить его в конце операции).
Я думаю, что это сработает, но:
1) Допустимо ли ограничивать приложения браузера одной вкладкой / экземпляром?
2) Должен ли я попытаться разрешить несколько экземпляров в версии 2.0?
Любые другие комментарии, помощь или совет?
Лучшим вариантом было бы избежать сохранения состояния взаимодействия пользователя в сеансе. Поместите его в скрытые поля формы или что-то, чтобы каждый клиентский запрос связывал с ним связанное с ним состояние. Если вас беспокоит вмешательство пользователя в него, используйте HMAC для предотвращения этого и, возможно, зашифруйте его, если он содержит вещи, которые пользователь не должен видеть.
В сеансе должно быть сохранено только состояние, которое должно быть разделено между вкладками, такими как идентификатор входа пользователя или что-то вроде корзины покупок.
В большинстве случаев вы можете сохранить в файле сеанса «последнюю запрошенную страницу» с флагами, указывающими, что пользователю не следует удалять его, если это один из этих критических флагов формы. Поэтому, если вы на form.php
и это no-move-off
form.php
, то любая новая загруженная страница должна form.php
«прервать или закрыть окно».
Вы не можете запретить пользователю открывать другую вкладку / окно, но вы можете помешать им перемещаться в другом месте вашего сайта в этих других окнах / вкладках.
Однако учтите, что это очень плохой пользовательский интерфейс. Представьте себе, если Amazon захватила вас на странице корзины покупок и никогда не позволяла вам перейти на другую страницу, не купив что-нибудь. Подумайте о том, как обновить свой код, чтобы несколько разных окон использовали одну и ту же форму.
В каждом браузере, поддерживающем просмотр с вкладками, было бы плохой пользовательский интерфейс, чтобы попытаться ограничить просмотр одной вкладкой (тогда вы можете также создать настольное приложение).
Один из способов решения этой проблемы – добавить маркер CSRF в свои формы (как скрытую переменную), который будет отправлен с запросом.
Ссылка CSRF
Существует много способов генерации токена, но по существу вы:
$_SESSION
<input type="hidden" name="{token name}" value="{token value}" />
Затем, когда форма отправляет вас, проверьте $_REQUEST['{token name}'] == $_SESSION[
{имя токена}] `.
Если этот токен отличается, вы знаете, что это не форма, которую вы изначально генерировали, и, следовательно, можете игнорировать запрос до тех пор, пока реальная форма не появится с правильным токеном.
Одно: если злоумышленник может понять, как вы генерируете токены CSRF, тогда они могут подделывать запросы.
Добавлен следующий скрипт после входа в систему (скажем, dashboard.php)
<script> $(document).ready(function() { $("a").attr("target", ""); if(typeof(Storage) !== "undefined") { sessionStorage.pagecount = 1; var randomVal = Math.floor((Math.random() * 10000000) + 1); window.name = randomVal; var url = "url to update the value in db(say random_value)"; $.post(url, function (data, url) { }); } else { var url = "url to remove random_value"; $.post(url, function (data, url) { sessionStorage.removeItem('pagecount'); sessionStorage.clear(); window.location = 'logout.php'; }); } }); </script>
Добавлен ниже сценарий в заголовке в остальной части моих страниц – «random_value» – от db для этого пользователя
<script> $(document).ready(function() { $("a").attr("target", "_self"); if(typeof(Storage) !== "undefined") { if (sessionStorage.pagecount) { if('<?=$random_value?>' == window.name) { sessionStorage.pagecount = Number(sessionStorage.pagecount) + 1; } else { var url = "url to remove random_value"; $.post(url, function (data, url) { sessionStorage.removeItem('pagecount'); sessionStorage.clear(); window.location = 'logout.php'; }); } } else { var url = "url to remove random_value"; $.post(url, function (data, url) { sessionStorage.removeItem('pagecount'); sessionStorage.clear(); window.location = 'logout.php'; }); } } else { var url = "url to remove random_value"; $.post(url, function (data, url) { sessionStorage.removeItem('pagecount'); sessionStorage.clear(); window.location = 'logout.php'; }); } }); </script>
Если бы я делал это сейчас, я бы, вероятно, скопировал одностраничное приложение AngularJs (хотя любая форма Js будет делать).
При запуске загляните в локальное хранилище для флага. Если установлено, откажитесь начать, с подходящим сообщением, еще установите флаг и запустите приложение.
Конечно, злоумышленник может обойти это, так как это не проверка на стороне сервера, но я бы просто отказался от поддержки такого.