Отправитель аутентификации HTTP через PHP

Каков правильный способ выхода из защищенной папки проверки подлинности HTTP?

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

Solutions Collecting From Web of "Отправитель аутентификации HTTP через PHP"

Mu. Не существует правильного пути , даже не совместимого с браузерами.

Это проблема, вытекающая из спецификации HTTP (раздел 15.6):

Существующие HTTP-клиенты и пользовательские агенты обычно сохраняют информацию аутентификации на неопределенный срок. HTTP / 1.1. не предоставляет метод для сервера, на который клиенты могут отбрасывать эти кэшированные учетные данные.

С другой стороны, в разделе 10.4.2 говорится:

Если запрос уже включил учетные данные авторизации, то ответ 401 указывает, что для этих учетных данных было отказано в авторизации. Если ответ 401 содержит ту же задачу, что и предыдущий ответ, и пользовательский агент уже попытался выполнить аутентификацию хотя бы один раз, тогда пользователю ДОЛЖЕН быть представлен объект, который был указан в ответе, поскольку этот объект может содержать соответствующую диагностическую информацию.

Другими словами, вы можете снова показать окно входа в систему (как говорит @Karsten ), но браузер не должен выполнять ваш запрос – так что не слишком сильно зависеть от этой функции (mis).

Метод, который хорошо работает в Safari. Также работает в Firefox и Opera, но с предупреждением.

 Location: http://logout@yourserver.example.com/ 

Это говорит браузеру, чтобы открыть URL с новым именем пользователя, переопределяя предыдущий.

Простой ответ заключается в том, что вы не можете надежно выйти из http-аутентификации.

Длинный ответ:
Http-auth (как и остальная часть спецификации HTTP) означает быть апатридом. Таким образом, «вход в систему» ​​или «выход из системы» на самом деле не является концепцией, которая имеет смысл. Лучший способ увидеть это – спросить, для каждого HTTP-запроса (и помните, что загрузка страницы обычно представляет собой несколько запросов), «разрешено ли вам делать то, что вы запрашиваете?». Сервер видит каждый запрос как новый и не связан с любыми предыдущими запросами.

Браузеры решили запомнить учетные данные, которые вы им сообщаете в первых 401, и повторно отправить их без явного разрешения пользователя на последующие запросы. Это попытка предоставить пользователю «зарегистрированную / выведенную» модель, которую они ожидают, но это просто kludge. Это браузер, который имитирует это сохранение состояния. Веб-сервер полностью не знает об этом.

Таким образом, «выход из системы», в контексте http-auth – это просто симуляция, предоставляемая браузером, и, таким образом, вне полномочий сервера.

Да, есть клоды. Но они ломают RESTful-ness (если это ценно для вас), и они ненадежны.

Если для аутентификации вашего сайта вам абсолютно необходима модель входа в систему / выходила из системы, лучшим вариантом является файл cookie отслеживания с сохранением состояния, хранящегося на сервере каким-либо образом (mysql, sqlite, flatfile и т. Д.). Это потребует оценки всех запросов, например, с помощью PHP.

Временное решение

Вы можете сделать это, используя Javascript:

 <html><head> <script type="text/javascript"> function logout() { var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } // code for IE else if (window.ActiveXObject) { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } if (window.ActiveXObject) { // IE clear HTTP Authentication document.execCommand("ClearAuthenticationCache"); window.location.href='/where/to/redirect'; } else { xmlhttp.open("GET", '/path/that/will/return/200/OK', true, "logout", "logout"); xmlhttp.send(""); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) {window.location.href='/where/to/redirect';} } } return false; } </script> </head> <body> <a href="#" onclick="logout();">Log out</a> </body> </html> , <html><head> <script type="text/javascript"> function logout() { var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } // code for IE else if (window.ActiveXObject) { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } if (window.ActiveXObject) { // IE clear HTTP Authentication document.execCommand("ClearAuthenticationCache"); window.location.href='/where/to/redirect'; } else { xmlhttp.open("GET", '/path/that/will/return/200/OK', true, "logout", "logout"); xmlhttp.send(""); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) {window.location.href='/where/to/redirect';} } } return false; } </script> </head> <body> <a href="#" onclick="logout();">Log out</a> </body> </html> 

Что сделано выше:

  • для IE – просто очистить кеш кеша и перенаправить куда-нибудь

  • для других браузеров – отправьте XMLHttpRequest за кулисами с именем входа и паролем logout. Нам нужно отправить его на какой-то путь, который вернет 200 OK к этому запросу (т. Е. Он не должен требовать HTTP-аутентификации).

Замените '/where/to/redirect' на какой-то путь для перенаправления после выхода из системы и замените '/path/that/will/return/200/OK' на какой-то путь на вашем сайте, который вернет 200 OK.

Обходное решение (не чистое, приятное (или даже работающее! См. Комментарии) решение):

Отключите его учетные данные один раз.

Вы можете переместить логику проверки подлинности HTTP на PHP, отправив соответствующие заголовки (если они не вошли в систему):

 Header('WWW-Authenticate: Basic realm="protected area"'); Header('HTTP/1.0 401 Unauthorized'); 

И разбор ввода:

 $_SERVER['PHP_AUTH_USER'] // httpauth-user $_SERVER['PHP_AUTH_PW'] // httpauth-password 

Поэтому отключение его учетных данных один раз должно быть тривиальным.

Выход из HTTP Basic Auth за два шага

Предположим, что у меня есть базовое пространство HTTP с именем «Защита паролем», и Боб вошел в систему. Чтобы выйти из системы, я делаю 2 запроса AJAX:

  1. Скрипт доступа / logout_step1. Он добавляет случайного временного пользователя в .htusers и отвечает своим логином и паролем.
  2. Скрипт доступа / logout_step2 аутентифицирован с использованием логина и пароля временного пользователя . Сценарий удаляет временного пользователя и добавляет этот заголовок в ответ: WWW-Authenticate: Basic realm="Password protected"

В этот момент браузер забыл учетные данные Боба.

Мое решение проблемы заключается в следующем. Вы можете найти функцию http_digest_parse , $realm и $users во втором примере этой страницы: http://php.net/manual/en/features.http-auth.php .

 session_start(); function LogOut() { session_destroy(); session_unset($_SESSION['session_id']); session_unset($_SESSION['logged']); header("Location: /", TRUE, 301); } function Login(){ global $realm; if (empty($_SESSION['session_id'])) { session_regenerate_id(); $_SESSION['session_id'] = session_id(); } if (!IsAuthenticated()) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$_SESSION['session_id'].'",opaque="'.md5($realm).'"'); $_SESSION['logged'] = False; die('Access denied.'); } $_SESSION['logged'] = True; } function IsAuthenticated(){ global $realm; global $users; if (empty($_SERVER['PHP_AUTH_DIGEST'])) return False; // check PHP_AUTH_DIGEST if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])) return False;// invalid username $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); // Give session id instead of data['nonce'] $valid_response = md5($A1.':'.$_SESSION['session_id'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); if ($data['response'] != $valid_response) return False; return True; } 

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

Trac – по умолчанию – использует HTTP-аутентификацию. Выход из системы не работает и не может быть исправлен:

  • Это проблема с самой схемой аутентификации HTTP, и мы ничего не можем сделать в Trac, чтобы исправить ее правильно.
  • В настоящее время нет обходного пути (JavaScript или другого), который работает со всеми основными браузерами.

От: http://trac.edgewall.org/ticket/791#comment:103

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

Мне нужно было сбросить авторизацию .htaccess, поэтому я использовал это:

 <?php if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); echo 'Text to send if user hits Cancel button'; exit; } ?> 

Нашел его здесь: http://php.net/manual/en/features.http-auth.php

Идите фигуру.

Ряд решений находится на этой странице, и он даже отмечает внизу: Lynx, не очищает auth, как другие браузеры;)

Я тестировал его на установленных браузерах и когда-то закрывался, каждый браузер, похоже, постоянно требует повторного запуска.

Это может быть не решение, которое нужно было искать, но я решил это так. У меня есть 2 скрипта для процесса выхода.

logout.php

 <?php header("Location: http://.@domain.com/log.php"); ?> 

log.php

 <?php header("location: https://google.com"); ?> 

Таким образом, я не получаю предупреждение, и моя сессия прекращается

AFAIK, нет чистого способа реализовать функцию «выхода» при использовании аутентификации htaccess (т.е. на основе HTTP).

Это связано с тем, что такая аутентификация использует код ошибки HTTP 401, чтобы сообщить браузеру, что учетные данные необходимы, и в этот момент браузер запрашивает у пользователя данные. С этого момента, пока браузер не будет закрыт, он всегда будет отправлять учетные данные без дальнейшего запроса.

Лучшее решение, которое я нашел до сих пор (это своего рода псевдокод, $isLoggedIn является псевдо переменной для http auth):

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

 function logout() { //$isLoggedIn = false; //This does not work (point of this question) $_SESSION['logout'] = true; } 

В том месте, где я проверяю подлинность, я расширяю условие:

 function isLoggedIn() { return $isLoggedIn && !$_SESSION['logout']; } 

Сессия несколько связана с состоянием HTTP-аутентификации, поэтому пользователь остается включенным, пока он держит браузер открытым и до тех пор, пока в браузере сохраняется HTTP-проверка.

В то время как другие верны, говоря, что невозможно выйти из базовой HTTP-аутентификации, есть способы реализовать аутентификацию, которая ведет себя аналогичным образом. Одно очевидное обращение – использовать auth_memcookie . Если вы действительно хотите реализовать базовую HTTP-аутентификацию (т. Е. Использовать диалоговые окна браузера для входа в trather, чем HTTP-форму), используя это – просто установите аутентификацию в отдельный .htaccess защищенный каталог, содержащий скрипт PHP, который перенаправляет обратно туда, куда пришел пользователь создание сеанса memcache.

Может быть, мне не хватает смысла.

Самый надежный способ, которым я нашел завершение HTTP-аутентификации, – закрыть браузер и все окна браузера. Вы можете закрыть окно браузера с помощью Javascript, но я не думаю, что вы можете закрыть все окна браузера.

Здесь много замечательных ответов. В моем конкретном случае я нашел чистое и простое исправление для выхода из системы. Мне еще предстоит проверить в Edge. На моей странице, на которой я вошел, я разместил ссылку для выхода из системы, подобную этой:

 <a href="https://MyDomainHere.net/logout.html">logout</a> 

И в голове этой страницы logout.html (которая также защищена .htaccess), у меня есть обновление страницы, похожее на это:

 <meta http-equiv="Refresh" content="0; url=https://logout:logout@MyDomainHere.net/" /> 

Если вы оставите слова «logout» на месте, чтобы очистить имя пользователя и пароль, кэшированные для сайта.

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

Единственный эффективный способ, с помощью которого я смог уничтожить учетные данные PHP_AUTH_DIGEST или PHP_AUTH_USER и PHP_AUTH_PW – это вызвать заголовок HTTP/1.1 401 Unauthorized .

 function clear_admin_access(){ header('HTTP/1.1 401 Unauthorized'); die('Admin access turned off'); }