PHP üzerinden HTTP kimlik doğrulama oturumu kapatma


151

HTTP kimlik doğrulaması korumalı klasöründe oturumu kapatmanın doğru yolu nedir ?

Bunu başarabilen geçici çözümler vardır, ancak potansiyel olarak tehlikelidirler çünkü buggy olabilirler veya belirli durumlarda / tarayıcılarda çalışmazlar. Bu yüzden doğru ve temiz bir çözüm arıyorum.


Lütfen çıkışınızın amacını belirtin. Bu zorunlu çıkış mı olmalı (kullanıcı devre dışı bırakma)? Kullanıcı için basit oturum kapatma işlevi? Başka herhangi bir şey?
Karsten

6
Bunun neden önemli olduğunu anlamıyorum, ancak her iki durumda da: uygulamadaki iç koşullara bağlı olarak devre dışı bırakma ve tipik oturum kapatma düğmesi. Lütfen neden önemli olduğunu açıklayın, doğrudan soruya düzenleyeceğim.
Josef Sábl

2
"Doğru ve temiz çözüm", kendi oturumu kapatma düğmesine sahip olan tarayıcılar, tıklandığında tarayıcının Kimlik Doğrulama başlıklarını göndermeyi durduracağı anlamına gelir ... Hayal edebileceğiniz bir şey var mı?
DanMan

1
Web Geliştirici Araç Çubuğu'nda böyle bir "düğme" bulunur.
Josef Sábl

Josef ne dedi: Firefox için web geliştirici araç çubuğu ->Miscellaneous -> Clear Private Data -> HTTP Authentication
Yarin

Yanıtlar:


103

Mu. Doğru bir yol yoktur , tarayıcılar arasında tutarlı olan bir yol bile yoktur.

Bu, HTTP spesifikasyonundan gelen bir sorundur (bölüm 15.6):

Mevcut HTTP istemcileri ve kullanıcı aracıları genellikle kimlik doğrulama bilgilerini süresiz olarak saklar. HTTP / 1.1. bir sunucunun istemcileri bu önbelleğe alınmış kimlik bilgilerini atması için yönlendirmesi için bir yöntem sağlamaz.

Öte yandan, bölüm 10.4.2 şöyle diyor:

İstek zaten Yetkilendirme kimlik bilgilerini içeriyorsa, 401 yanıtı bu kimlik bilgileri için yetkinin reddedildiğini gösterir. 401 yanıtı, önceki yanıtla aynı sorguyu içeriyorsa ve kullanıcı aracısı en az bir kez kimlik doğrulama girişiminde bulunmuşsa, kullanıcıya ilgili tanılama bilgilerini içerebileceğinden yanıtta verilen varlığa SUNULMALIDIR.

Başka bir deyişle, giriş kutusunu tekrar gösterebilirsiniz ( @Karsten'in söylediği gibi), ancak tarayıcının isteğinizi yerine getirmesi gerekmez - bu nedenle bu (yanlış) özelliğe çok fazla bağımlı olmayın.


9
Bu, RFC'deki bir hatadır. W3C düzeltilemeyecek kadar tembel. Çok üzücü.
Erik Aronesty

@Jonathan Hanson'un önerdiği gibi , HTTP kimlik doğrulamasıyla birlikte bir izleme çerezi kullanabilirsiniz. Bu benim için en iyi yöntem.
machineaddict

61

Safari'de güzel çalışan yöntem. Firefox ve Opera'da da çalışır, ancak bir uyarı ile.

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

Bu, tarayıcıya URL'yi yeni kullanıcı adıyla açmasını ve bir öncekini geçersiz kılmasını söyler.


14
RFC 3986 (URI: Genel Sözdizimi) bölümüne göre 3.2.1. (Kullanıcı Bilgileri) kullanımdan user:password@hostkaldırılmıştır. Sadece kullanmak http://logout@yourserver.example.com/çoğu durumda değildir ve çalışmalıdır.
aef

1
@andho: evet, bu bir yönlendirme. 302 statüsü ile kullanmalısınız.
Kornel

1
Görünüşe göre logout@yourserver.example.com için basit bir bağlantı da PHP'de bir http yönlendirmesi yerine (bu URL'ye bir "bağlantıyı kes" bağlantısı) çalışıyor mu?
moala

4
Dikkat: Yeniden oturum açtıktan sonra (oturum kapatma istemiyle oturum aç) oturum açıldığında göreli yol kullanan form gönderme başarısız olabilir, çünkü adres sunucunuz
Jason

1
logout@yourserver.example.com , Chrome'da sınırsız sayıda sorunla çalışır, ancak Firefox'ta bir güvenlik sorgusunu ister. logout: true@sunucu.example.com dozu Firefox'u güvenlik açığı haline getirmez. İki url'den hiçbiri IE8'de çalışmıyor: /
Thor A. Pedersen

46

Basit cevap, http-kimlik doğrulamasından güvenilir bir şekilde çıkış yapamamanızdır.

Uzun cevap:
Http-auth (HTTP spesifikasyonunun geri kalanı gibi) vatansızdır. Dolayısıyla, "giriş yapılmış" veya "çıkış yapılmış" olmak gerçekten mantıklı bir kavram değildir. Bunu sormanın en iyi yolu, her HTTP isteği için (ve bir sayfa yükünün genellikle birden fazla istek olduğunu unutmayın), "istediğinizi yapmanıza izin verilir mi?" Sunucu her isteği yeni ve önceki isteklerle ilgisiz olarak görür.

Tarayıcılar, ilk 401'de belirttiğiniz kimlik bilgilerini hatırlamayı ve kullanıcının sonraki isteklerde açık izni olmadan yeniden göndermeyi seçti. Bu, kullanıcıya bekledikleri "giriş / çıkış" modelini verme girişimidir, ancak tamamen bir çamurdur. Bu durumun sürekliliğini simüle eden tarayıcıdır . Web sunucusu tamamen farkında değil.

Yani "çıkış", http-auth bağlamında sadece tarayıcı tarafından sağlanan bir simülasyon ve böylece sunucunun yetkisi dışında.

Evet, kludges var. Ama RESTful-ness'i kırıyorlar (eğer sizin için değerliyse) ve güvenilmezler.

Sitenizin kimlik doğrulaması için kesinlikle oturum açmış / oturumu kapatılmış bir modele ihtiyacınız varsa, en iyi bahis, sunucuda bir şekilde depolanan durumun kalıcılığıyla (mysql, sqlite, flatfile, vb.) Bir izleme çerezidir. Bu, tüm isteklerin örneğin PHP ile değerlendirilmesini gerektirecektir.


26

Geçici çözüm

Javascript kullanarak bunu yapabilirsiniz:

<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>

Yukarıda yapılanlar:

  • IE için - yalnızca önbellek önbelleğini temizleyin ve bir yere yönlendirin

  • diğer tarayıcılar için - 'oturum kapatma' oturum açma adı ve şifresi ile perde arkasına bir XMLHttpRequest gönderin. Bu talebe 200 OK döndürecek bir yola göndermemiz gerekiyor (yani HTTP kimlik doğrulaması gerektirmemelidir).

Oturumu '/where/to/redirect'kapattıktan sonra yönlendirme yapmak için '/path/that/will/return/200/OK'bir yolla değiştirin ve sitenizde 200 Tamam döndürecek bir yolla değiştirin .


5
Başka bir kullanıcı olarak oturum açmak geçici bir çözümdür. Ama bu gerçekten işe yarıyor ve daha fazla krediyi hak ediyor.
Charlie Rudenstål

2
Bunun en iyi cevap olduğunu düşünüyorum. Benzer bir sorunun bu cevabında belirtildiği gibi , şifrenin rastgele seçilmesinin bir avantajı olabilir.
zelanix

2
İstediğim buydu - tüm tarayıcılarda sorunsuz çalıştı. Devraldığım "çıkış" sayfasını korudum. Mutlaka JS (belki de mantıksız) kullanmak istemedim, ancak diğer cevapların tüm çapraz tarayıcı sorunları vardı ve bu mükemmel çalıştı.
dgig

Bu işi açıklandığı şekilde yapamam. Güvenli bölgeye geri döndüğümde, tarayıcı başlıkta son kullanılan geçerli kimlik bilgilerini göndererek kendini yeniden doğrular. Ancak, küçük bir değişiklikle benim için çalıştı. 200 OK yanıtını güvenli alandaki aynı Bölge'ye sahip bir başlıkla değiştirdim, ancak yalnızca bir "oturum kapatma: oturum kapatma" kullanıcı / geçişini kabul ettim. Bu şekilde, kullanıcı bu "oturumu kapat" kullanıcısıyla oturum açmıştır ve bu güvenli bölgeye geri döndüğünde yeniden deneyen kullanıcıdır. Güvenli alan bu kullanıcıyı / parolayı reddeder, böylece kullanıcı kimlik bilgilerini değiştirebilir.
jonaguera

2
Açıklandığı gibi bu çalışmaz. Chrome 40 ve Firefox 35'te test edildi.
funforums

13

Geçici çözüm (temiz, hoş değil (hatta çalışıyor! Yorumlara bakın) çözümü):

Kimlik bilgilerini bir kez devre dışı bırak.

HTTP kimlik doğrulama mantığınızı uygun başlıkları göndererek PHP'ye taşıyabilirsiniz (giriş yapmadıysanız):

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

Ve girdiyi ayrıştırmak:

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

Bu yüzden kimlik bilgilerini bir kez devre dışı bırakmak önemsiz olmalıdır.


18
Bu çözüm ile sorun şudur: IE kimlik bilgileri Tamam olmadığını bilmek izin. Boş alanlarla oturum açma iletişim kutusunu görüntüler (şifre yöneticisinde saklanan değerleri göstermez). Ancak, sayfayı iptal et ve yenile'yi tıkladığınızda depolanan kimlik bilgilerini gönderir ve böylece tekrar oturum açar.
Josef Sábl

downvoted; Josef Sable'ın yorumladığı gibi, bu sorunu elinizde çözmez.
Chris Wesseling

7

HTTP Temel Kimlik Doğrulama'dan iki adımda çıkış

Diyelim ki “Şifre korumalı” adında bir HTTP Temel Yetkilendirme alanım var ve Bob giriş yaptı. Oturumu kapatmak için 2 AJAX isteği yapıyorum:

  1. Komut dosyasına / logout_step1'e erişin. .Htusers kullanıcısına rasgele geçici bir kullanıcı ekler ve kullanıcı adı ve şifresi ile yanıt verir.
  2. Geçici kullanıcının oturum açma adı ve şifresi ile doğrulanmış erişim script / logout_step2 . Komut dosyası geçici kullanıcıyı siler ve yanıta şu başlığı ekler:WWW-Authenticate: Basic realm="Password protected"

Bu noktada tarayıcı Bob'un kimlik bilgilerini unuttu.


1
Vaov! Bu, tamamen yaratıcı bir şey olsa bile, tamamen yaratıcılık için bir +1 hak ediyor.
Andy Triggs

7

Soruna çözümüm şudur. Sen fonksiyonunu bulabilirsiniz http_digest_parse, $realmve $usersbu sayfanın ikinci örnekteki: 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

Tipik olarak, bir tarayıcı kullanıcıdan kimlik bilgilerini sorduktan ve belirli bir web sitesine sağladıktan sonra, bunu sormadan yapmaya devam edecektir. İstemci tarafında çerezleri temizlemenin çeşitli yollarının aksine, tarayıcıdan sağlanan kimlik doğrulama bilgilerini unutmasını istemenin benzer bir yolunu bilmiyorum.


Firefox'ta "Özel verileri sil" seçeneğini belirlediğinizde kimliği doğrulanmış oturumları silme seçeneği olduğuna inanıyorum
Kristian J.

1
Ayrıca Firefox için Web Geliştirici Araç Çubuğu uzantısı HTTP Kimlik Doğrulamalarını silme özelliği sunar. Ancak bu gerçekten söz konusu değil, çünkü kullanıcılarımızdan FF uzantılarını indirmelerini veya şifreli tarayıcı komutlarını çalıştırmasını
isteyemeyiz

2
Firefox'un HTTP kimlik doğrulamasından çıkış yapmanın varsayılan yolu "Araçlar"> "Yakın Geçmişi Temizle ..." altında, "Etkin Girişler" onay kutusu olarak kullanılabilir. Bu sezgisel değildir ve yalnızca bir alan adından çıkış yapmanıza izin vermez, her sayfadan çıkış yaparsınız.
aef

2

Trac - varsayılan olarak - HTTP Kimlik Doğrulaması da kullanır. Çıkış çalışmıyor ve düzeltilemiyor:

  • Bu, HTTP kimlik doğrulama düzeninin kendisiyle ilgili bir sorundur ve Trac'de düzgün bir şekilde düzeltmek için yapabileceğimiz hiçbir şey yoktur.
  • Şu anda tüm büyük tarayıcılarla çalışan bir geçici çözüm (JavaScript veya diğer) yoktur.

Gönderen: http://trac.edgewall.org/ticket/791#comment:103

Görünüşe göre bu soruya çalışan bir cevap yok, bu sorun yedi yıl önce bildirildi ve bu çok mantıklı: HTTP vatansız. Kimlik doğrulama kimlik bilgileriyle bir istek yapılır veya yapılmaz. Ancak bu, isteği alan sunucunun değil, isteği gönderen bir konudur. Sunucu yalnızca bir istek URI'sının yetkilendirmeye ihtiyacı olup olmadığını söyleyebilir.


2

Bunu kullandım .htaccess yetkilendirmesini sıfırlamak için gerekli:

<?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;
}
?>

Burada buldum : http://php.net/manual/en/features.http-auth.php

Git şekil.

Bu sayfada bir dizi çözüm bulunur ve altta bile not alır: Lynx, diğer tarayıcılar gibi yetkileri temizlemez;)

Yüklü tarayıcılarımda test ettim ve bir kez kapatıldığında, her tarayıcı sürekli olarak yeniden giriş gerektiriyor gibi görünüyor.


Bu çalışmıyor gibi görünüyor, herhangi bir pop-up giriş kutusu olmadan iptal metni alıyorum.
Michael

Görünen o ki, gönderen WWW-Authenticatesoruna neden oluyordu , ondan kurtulmak beni otomatik olarak kapattı.
Michael

Ve tersine, gibi görünüyor DEĞİL gönderme WWW-AuthenticateBir tarayıcıda (Chrome) sorunun çözümü ise kimlik bilgilerini hatırlar ve otomatik yeniden giriş sonuçlanan sonraki istek üzerine bunları göndermek için başka bir tarayıcı (Firefox) neden olur! Ahh!
Michael

Daha sonra UA'ya bakın ve birini ya da diğerini bir çözüm gibi görün
Lennart Rolland

2

Bu aranan çözüm olmayabilir ama ben böyle çözdüm. Çıkış işlemi için 2 komut dosyası var.

logout.php

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

log.php

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

Bu şekilde bir uyarı alamıyorum ve oturumum sona erdi


1
Bu benim için gerçekten işe yarayan tek çözümdü! Firefox 37 ve Chromium 41'de test edildi
zesaver

1

AFAIK, htaccess (yani HTTP tabanlı) kimlik doğrulamasını kullanırken "oturum kapatma" işlevini uygulamanın temiz bir yolu yoktur.

Bunun nedeni, bu kimlik doğrulamasının tarayıcıya kimlik bilgilerinin gerekli olduğunu söylemek için HTTP hata kodunu '401' kullanmasıdır; bu noktada tarayıcı, kullanıcıdan ayrıntıları ister. O andan itibaren, tarayıcı kapanana kadar, kimlik bilgilerini her zaman daha fazla sormadan gönderir.


1

Şimdiye kadar bulduğum en iyi çözüm (bir çeşit sahte kod, $isLoggedInhttp auth için sahte değişken):

"Çıkış" sırasında kullanıcının oturumu kapattığını belirten bazı bilgileri oturumda saklayın.

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

Kimlik doğrulamasını kontrol ettiğim yerde durumu genişletiyorum:

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

Oturum http kimlik doğrulama durumuna bir şekilde bağlanır, böylece kullanıcı tarayıcıyı açık tuttuğu ve http kimlik doğrulaması tarayıcıda devam ettiği sürece oturumu kapalı kalır.


4
Http temel kimlik doğrulaması RESTful olsa da, oturumlar değildir.
Kasım'da 09:

1

Belki de noktayı kaçırıyorum.

HTTP Kimlik Doğrulamasını sonlandırmanın en güvenilir yolu tarayıcıyı ve tüm tarayıcı pencerelerini kapatmaktır. Bir tarayıcı penceresini Javascript kullanarak kapatabilirsiniz, ancak tüm tarayıcı pencerelerini kapatabileceğinizi sanmıyorum.


fyi bazı sekmeler açıksa bazı tarayıcılar bir pencereyi kapatmaz, bu yüzden nokta gerçekten tartışmalıdır
scape

O uzun yıllar önce pencereyi kapatmadan oturum kapatma düğmesini uygulamak için görev vardı :-) Ama belki "pencereyi kapatmamak" üzerinde durmayacaklardı. Ama hey, bu birisi için işe yarayacak basit bir çözüm ve dürüst olmak için o zaman özledim.
Josef Sábl

1

Tek etkili yol ı ettik silip bulunmuştur PHP_AUTH_DIGESTya PHP_AUTH_USERVE PHP_AUTH_PWkimlik başlığını çağırmaktır HTTP/1.1 401 Unauthorized.

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

0

Diğerleri, temel http kimlik doğrulamasından çıkış yapmanın imkansız olduğunu söylerken haklı olsalar da, benzer şekilde davranan kimlik doğrulamayı uygulamanın yolları vardır . Açık bir yaklaşım, auth_memcookie kullanmaktır . Bunu kullanarak gerçekten Temel HTTP kimlik doğrulaması uygulamak istiyorsanız (yani, bir HTTP formundan daha fazla oturum açmak için tarayıcı iletişim kutularını kullanın) - kimlik doğrulamasını, kullanıcının geldiği yere geri yönlendiren bir PHP komut dosyası içeren ayrı bir .htaccess korumalı dizine ayarlayın memcache oturumunun oluşturulması.


0

Burada çok sayıda harika - karmaşık - cevap var. Benim özel durumumda çıkış için temiz ve basit bir düzeltme buldum. Edge'de henüz test yapmadım. Giriş yaptığım sayfamda buna benzer bir çıkış bağlantısı yerleştirdim:

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

Ve bu logout.html sayfasının başlangıcında (.htaccess tarafından da korunur) buna benzer bir sayfa yenileme var:

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

Site için önbelleğe alınan kullanıcı adını ve şifreyi temizlemek için "oturumu kapat" kelimelerini bırakacağınız yer.

En baştan doğrudan giriş yapabilmek için birden fazla sayfanın gerekli olması durumunda, bu giriş noktalarının her birinin kendi ilgili logout.html sayfasına ihtiyacı olacağını kabul edeceğim. Aksi takdirde, oturum açma hedefine ulaşmak için bir deyimin girilmesini gerektirerek, gerçek oturum açma isteminden önce işleme ek bir ağ geçidi denetleyicisi adımı ekleyerek oturumu merkezileştirebilirsiniz.


1
ileriye doğru hareket ederken, bu işe yarar, oturumu kapatır, ancak tarayıcı geri geçmişi yine de oturumu yeniden oluşturabilir.
johnwayne
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.