Выход HTTP аутентификации через PHP

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

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

17 ответов


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

это проблема, которая исходит из спецификация HTTP (раздел 15.6):

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

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

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

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


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

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

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


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

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

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

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

Да, есть несколько костылей. Но они нарушают покой (если это имеет для вас ценность), и они ненадежны.

Если вам абсолютно необходима модель входа / выхода для аутентификации вашего сайта, лучше всего использовать файл 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>

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

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

  • для других браузеров - отправить 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 Basic Auth realm с именем "Password protected", и Боб вошел в систему. Чтобы выйти из системы, я делаю 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;
}

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


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

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

From: 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, не очищает аутентификацию, как другие браузеры;)

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


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

выход из системы.в 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, - закрыть браузер и все окна браузера. Вы можете закрыть окно браузера с помощью Javascript, но я не думаю, что вы можете закрыть все окна браузера.


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


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

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

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

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

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

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


единственный действенный способ, который я нашел, чтобы уничтожить 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');
}