PHP를 통한 HTTP 인증 로그 아웃


151

HTTP 인증 보호 폴더에서 로그 아웃 하는 올바른 방법 은 무엇입니까 ?

이것을 달성 할 수있는 해결 방법이 있지만 버그가 있거나 특정 상황 / 브라우저에서 작동하지 않기 때문에 잠재적으로 위험합니다. 그래서 나는 정확하고 깨끗한 해결책을 찾고 있습니다.


로그 아웃 목적을 지정하십시오. 강제 로그 아웃이어야합니까 (사용자 비활성화)? 사용자를위한 간단한 로그 아웃 기능? 다른 거있어?
Karsten

6
왜 이것이 중요한지 이해하지 못하지만 응용 프로그램의 내부 조건 및 일반적인 로그 아웃 버튼을 기반으로 한 비활성화입니다. 왜 중요한지 설명 해주세요. 질문으로 직접 편집하겠습니다.
Josef Sábl

2
"올 바르고 깨끗한 솔루션"은 클릭하면 브라우저가 Auth 헤더 전송을 중지하게하는 자체 로그 아웃 버튼이있는 브라우저입니다.
DanMan

1
웹 개발자 툴바에는 "버튼"이 있습니다.
Josef Sábl

Josef의 말 : Firefox 용 웹 개발자 툴바 ->Miscellaneous -> Clear Private Data -> HTTP Authentication
Yarin

답변:


103

뮤 브라우저간에 일관된 방식이 아닌 올바른 방법은 없습니다.

이것은 HTTP 사양 (섹션 15.6) 에서 발생하는 문제입니다 .

기존 HTTP 클라이언트 및 사용자 에이전트는 일반적으로 인증 정보를 무기한 보유합니다. HTTP / 1.1. 서버가 클라이언트에게 이러한 캐시 된 자격 증명을 삭제하도록 지시하는 방법을 제공하지 않습니다.

반면에 10.4.2 절 은 다음과 같이 말합니다.

요청에 이미 인증 자격 증명이 포함 된 경우 401 응답은 해당 자격 증명에 대한 인증이 거부되었음을 나타냅니다. 401 응답에 이전 응답과 동일한 시도가 포함되어 있고 사용자 에이전트가 이미 한 번 이상 인증을 시도한 경우 응답에 제공된 엔티티가 사용자에게 표시되어야합니다. 해당 엔티티는 관련 진단 정보를 포함 할 수 있기 때문입니다.

즉, @Karsten이 말한 것처럼 로그인 상자를 다시 표시 할 수있지만 브라우저는 요청을 존중할 필요가 없으므로이 (미스) 기능에 너무 의존하지 마십시오.


9
이것은 RFC의 버그입니다. W3C가 너무 게으르다 고칠 수 없습니다. 너무 슬퍼.
Erik Aronesty

@Jonathan Hanson이 아래 에서 제안한 것처럼 HTTP 인증과 함께 추적 쿠키를 사용할 수 있습니다. 이것은 나에게 가장 좋은 방법입니다.
machineaddict

61

Safari에서 잘 작동하는 방법. Firefox 및 Opera에서도 작동하지만 경고가 표시됩니다.

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

이렇게하면 브라우저가 새 사용자 이름으로 URL을 열도록하여 이전 사용자 이름보다 우선합니다.


14
RFC 3986 (URI : 일반 구문) 섹션 3.2.1에 따라. (사용자 정보)의 사용 user:password@host이 권장되지 않습니다. http://logout@yourserver.example.com/대부분의 경우 에만 사용하는 것은 좋지 않으며 작동해야합니다.
aef

1
@andho : 예, 리디렉션입니다. 상태 302와 함께 사용해야합니다.
Kornel

1
분명히 logout@yourserver.example.com에 대한 간단한 링크 는 PHP의 http 리디렉션 대신 작동합니다 (이 URL에 대한 "연결 끊기"링크).
moala

4
주의 : 상대 경로를 사용한 양식 제출은 주소가 여전히 yourserver.example.com/path가 아니라 logout@yourserver.example.com/path 이므로 재 로그인 (로그 아웃 프롬프트로 로그인) 후에 수행 될 때 실패 할 수 있습니다. /
Jason

1
logout@yourserver.example.com 은 Chrome에서 whitout 문제를 일으키지 만 Firefox에서는 보안 문제를 묻습니다. logout : true@yourserver.example.com 은 Firefox promt를 보안 문제로 만들지 않습니다. 어느 IE8에서 두 개의 URL 작업 : /
토르 A. 페데르센

46

간단한 대답은 http 인증에서 안정적으로 로그 아웃 할 수 없다는 것입니다.

긴 대답 :
Http-auth (HTTP 사양의 나머지 부분과 마찬가지로)는 stateless입니다. 따라서 "로그인"또는 "로그 아웃"은 실제로 의미가있는 개념이 아닙니다. 이를 확인하는 가장 좋은 방법은 각 HTTP 요청에 대해 요청하는 것입니다 (그리고 페이지로드는 일반적으로 여러 요청임을 기억하십시오). "요청한 작업을 수행 할 수 있습니까?" 서버는 각 요청을 새로운 요청으로 간주하며 이전 요청과 관련이 없습니다.

브라우저는 처음 401에서 제공 한 자격 증명을 기억하고 후속 요청에 대한 사용자의 명시적인 권한없이 다시 전송하도록 선택했습니다. 이는 사용자에게 "로그인 / 로그 아웃"모델을 제공하려는 시도이지만 순전히 실패입니다. 이 상태 지속성을 시뮬레이션 하는 브라우저 입니다. 웹 서버는 완전히 알지 못합니다.

따라서 http-auth와 관련하여 "로그 아웃"은 순전히 브라우저가 제공하는 시뮬레이션이며 서버 권한 외부에 있습니다.

그렇습니다. 그러나 그들은 RESTful-ness (당신에게 가치가있는 경우)를 깨뜨리고 신뢰할 수 없습니다.

사이트 인증을 위해 로그인 / 로그 아웃 된 모델이 절대적으로 필요한 경우 가장 좋은 방법은 추적 쿠키이며 서버에 상태가 지속되는 방식 (mysql, sqlite, flatfile 등)을 유지하는 추적 쿠키입니다. 이를 위해서는 모든 요청을 예를 들어 PHP로 평가해야합니다.


26

해결 방법

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의 경우 -인증 캐시를 지우고 어딘가에 리디렉션하십시오.

  • 다른 브라우저의 경우 - '로그 아웃'로그인 이름과 비밀번호를 사용하여 XMLHttpRequest를이면에서 보냅니다. 요청에 200 OK를 반환하는 경로로 보내야합니다 (즉, HTTP 인증이 필요하지 않음).

교체 '/where/to/redirect'로그 아웃 한 후 리디렉션 및 대체 어떤 경로로 '/path/that/will/return/200/OK'200 OK를 반환합니다 귀하의 사이트에 대한 몇 가지 경로.


5
다른 사용자로 로그인하는 것은 다소 해결 방법입니다. 그러나 이것은 실제로 작동하며 더 많은 크레딧을받을 자격이 있습니다.
Charlie Rudenstål

2
이것이 가장 좋은 대답이라고 생각합니다. 비슷한 질문에 대한 답변 에서 언급했듯이 암호를 무작위로 지정하면 이점이있을 수 있습니다.
zelanix

2
이것은 내가 원했던 것입니다-문제없이 모든 브라우저에서 작동했습니다. 그대로 상속받은 "로그 아웃"페이지를 유지했습니다. JS를 사용하고 싶지는 않았지만 (비합리적으로) 다른 답변에는 브라우저 간 문제가 있었으며 완벽하게 작동했습니다.
dgig

설명 된 방식으로이 작업을 수행 할 수 없습니다. 보안 영역으로 돌아 가면 브라우저는 마지막으로 사용 된 유효한 자격 증명을 헤더에 전송하여 다시 인증합니다. 그러나 약간의 변경으로 그것은 나를 위해 일했습니다. 보안 영역의 영역이 동일한 헤더로 200 OK 응답을 변경했지만 "logout : logout"사용자 / 패스 만 허용합니다. 이러한 방식으로 사용자는이 "로그 아웃"사용자로 로그인했으며 보안 영역으로 돌아갈 때 다시 시도하는 사용자입니다. 보안 영역은이 사용자 / 패스를 거부하므로 사용자가 자격 증명을 변경할 수 있습니다.
jonaguera

2
설명 된대로 작동하지 않습니다. Chrome 40 및 Firefox 35에서 테스트되었습니다.
funforums

13

해결 방법 (깨끗하고 훌륭하지 않거나 심지어 작동합니다! 의견 참조) 솔루션 :

자격 증명을 한 번 비활성화하십시오.

적절한 헤더를 보내서 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

따라서 자격 증명을 한 번 비활성화하면 사소한 것입니다.


18
이 솔루션의 문제점은 다음과 같습니다. IE에 자격 증명이 정상이 아님을 알립니다. 빈 필드가있는 로그인 대화 상자를 표시합니다 (비밀번호 관리자에 저장된 값은 표시하지 않음). 그러나 취소를 클릭하고 페이지를 새로 고치면 저장된 자격 증명이 전송되어 다시 로그인합니다.
Josef Sábl

공감; Josef Sable이 언급했듯이, 이것은 당면한 문제를 해결하지 못합니다.
Chris Wesseling 2012 년

7

두 단계로 HTTP 기본 인증에서 로그 아웃

"Password protected"라는 HTTP 기본 인증 영역이 있고 Bob이 로그인했다고 가정합니다. 로그 아웃하려면 2 개의 AJAX 요청을합니다.

  1. 액세스 스크립트 / logout_step1. .htusers에 임의의 임시 사용자를 추가하고 로그인 및 비밀번호로 응답합니다.
  2. 액세스 스크립트 / logout_step2 임시 사용자의 로그인과 암호로 인증 . 스크립트는 임시 사용자를 삭제하고 응답에이 헤더를 추가합니다.WWW-Authenticate: Basic realm="Password protected"

이 시점에서 브라우저는 Bob의 자격 증명을 잊었습니다.


1
와! 이것은 완전히 너트해야 할 일이더라도 진정한 독창성을 위해 +1이 필요합니다.
Andy Triggs

7

문제에 대한 나의 해결책은 다음과 같습니다. 당신은 기능을 찾을 수 있습니다 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;
}

4

일반적으로 브라우저가 사용자에게 자격 증명을 요청하고이를 특정 웹 사이트에 제공 한 후에는 추가 프롬프트없이 계속 그렇게합니다. 클라이언트 측에서 쿠키를 지우는 다양한 방법과는 달리 브라우저에 제공된 인증 자격 증명을 잊어달라고 요청하는 비슷한 방법을 모르겠습니다.


Firefox에서 "비공개 데이터 삭제"를 선택할 때 인증 된 세션을 삭제하는 옵션이 있다고 생각합니다.
Kristian J.

1
또한 Firefox 용 Web Developer Toolbar 확장 기능은 HTTP 인증을 삭제하는 기능을 제공합니다. 그러나 우리가 실제로 사용자에게 FF 확장 프로그램을 다운로드하거나 암호 브라우저 명령을 실행하도록 요청할 수 없기 때문에 이것은 의문의 여지가 없습니다 :-)
Josef Sábl

2
HTTP 인증에서 Firefox의 기본 로그 아웃 방법은 "도구"> "최근 기록 지우기 ..."에서 "활성 로그인"확인란으로 사용할 수 있습니다. 이것은 직관적이지 않으며 한 도메인에서만 로그 아웃 할 수 없으며 모든 페이지에서 항상 로그 아웃됩니다.
aef

2

Trac-기본적으로 HTTP 인증도 사용합니다. 로그 아웃이 작동하지 않으며 수정할 수 없습니다.

  • 이것은 HTTP 인증 체계 자체의 문제이며, Trac에서 제대로 수정하기 위해 할 수있는 일은 없습니다.
  • 현재 모든 주요 브라우저에서 작동하는 해결 방법 (JavaScript 또는 기타)이 없습니다.

보낸 사람 : http://trac.edgewall.org/ticket/791#comment:103

이 질문에 대한 실제 답변이없는 것처럼 보이며 7 년 전에 문제 가보고되었으며 HTTP는 상태가 없습니다. 인증 자격 증명을 사용하여 요청을 수행하거나 수행하지 않습니다. 그러나 그것은 서버가 아닌 클라이언트가 요청을 보내는 문제입니다. 서버는 요청 URI에 인증이 필요한지 여부 만 말할 수 있습니다.


2

.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는 다른 브라우저와 마찬가지로 인증을 지우지 않습니다.)

설치된 브라우저에서 테스트 한 후 닫히면 각 브라우저는 일관되게 다시 입력해야합니다.


이것은 작동하지 않는 것 같습니다. 팝업 로그인 상자가 없으면 취소 텍스트가 나타납니다.
Michael

전송하면 WWW-Authenticate문제가 발생하여 자동으로 로그 아웃 된 것을 제거합니다.
Michael

그리고 반대로, 것 같습니다 하지 를 보내는 WWW-Authenticate하나 개의 브라우저 (크롬)의 문제를 해결하면서하는 자격 증명을 기억하고 자동 재 로그인의 결과로, 다음 요청에 그들을 보내 다른 브라우저 (파이어 폭스)의 원인! 아아!
Michael

그리고 UA보고 하나를 수행하거나 다른 해결책처럼 보인다
레나 롤랑

2

이것은 찾은 솔루션이 아닐 수도 있지만 다음과 같이 해결했습니다. 로그 아웃 프로세스를위한 2 개의 스크립트가 있습니다.

logout.php

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

log.php

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

이렇게하면 경고 메시지가 표시되지 않고 세션이 종료됩니다.


1
이것은 실제로 나를 위해 일한 유일한 솔루션이었습니다! Firefox 37 및 Chromium 41에서 테스트
zesaver

1

AFAIK, htaccess (예 : HTTP 기반) 인증을 사용할 때 "로그 아웃"기능을 구현할 수있는 확실한 방법은 없습니다.

이러한 인증은 HTTP 오류 코드 '401'을 사용하여 자격 증명이 필요하다는 것을 브라우저에 알리기 때문에 브라우저는 사용자에게 세부 정보를 요구합니다. 그때부터 브라우저가 닫힐 때까지 추가 프롬프트없이 항상 자격 증명을 보냅니다.


1

지금까지 찾은 가장 좋은 해결책은 (의사 코드의 일종이며, $isLoggedInhttp auth의 의사 변수입니다) :

"로그 아웃"할 때 사용자가 실제로 로그 아웃되었다는 정보를 세션에 저장하십시오.

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

인증을 확인하는 장소에서 조건을 확장합니다.

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

세션은 http 인증 상태와 다소 연결되어 있으므로 사용자가 브라우저를 열어두고 브라우저에서 http 인증이 유지되는 한 로그 아웃 상태를 유지합니다.


4
http 기본 인증은 RESTful이지만 세션은 그렇지 않습니다.
deamon

1

어쩌면 내가 요점을 잃어 버렸을 수도 있습니다.

HTTP 인증을 종료하는 가장 확실한 방법은 브라우저와 모든 브라우저 창을 닫는 것입니다. Javascript를 사용하여 브라우저 창을 닫을 수는 있지만 모든 브라우저 창을 닫을 수는 없습니다.


참고하시기 바랍니다 일부 브라우저 닫지 점은 논쟁 정말 그래서 유일한 탭 열기, 만약 윈도우 것이다
풍경이

그 오래 전에 창을 닫지 않고 로그 아웃 버튼을 구현하는 작업이있었습니다. :-) 그러나 "창을 닫지 않습니다"에 머물지 않을 것입니다. 그러나 이것은 누군가에게 효과적 일 수있는 간단한 솔루션이며 정직하게 생각하지 못했습니다.
Josef Sábl

1

PHP_AUTH_DIGEST또는 PHP_AUTH_USERAND PHP_AUTH_PW자격 증명 을 지우는 유일한 효과적인 방법 은 header를 호출하는 것 HTTP/1.1 401 Unauthorized입니다.

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

0

다른 사람이 말하는에서 올바른 동안의 불가능 기본 HTTP 인증에서 로그 아웃에 인증을 구현하는 방법이있다 행동 과 유사합니다. 명백한 접근 방법 중 하나는 auth_memcookie를 사용하는 입니다. 이것을 사용하여 기본 HTTP 인증을 구현하려면 (즉, HTTP 양식보다 더 많이 로그인하려면 브라우저 대화 상자를 사용하십시오) 인증을 설정하십시오. memcache 세션 생성


0

여기에는 많은 복잡한 답변이 있습니다. 내 특별한 경우에는 로그 아웃에 대한 깨끗하고 간단한 수정 사항을 찾았습니다. 아직 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.html 페이지가 필요하다는 것을 인정합니다. 그렇지 않으면 실제 로그인 프롬프트 전에 프로세스에 추가 게이트 키퍼 단계를 도입하여 로그 아웃을 중앙 집중화 할 수 있으며, 로그인 대상에 문구를 입력해야합니다.


1
앞으로 이동하면 작동하지만 로그 아웃되지만 브라우저 다시 기록은 여전히 ​​세션을 다시 설정할 수 있습니다.
johnwayne
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.