Wie kann verhindert werden, dass der Browser das grundlegende Authentifizierungs-Popup aufruft und 401-Fehler mit Jquery behandelt?

105

Ich muss eine Autorisierungsanfrage mit der Basisauthentifizierung senden. Ich habe dies erfolgreich mit jquery implementiert. Wenn ich jedoch einen 401-Fehler erhalte, wird das Popup-Fenster für den grundlegenden Authentifizierungsbrowser geöffnet und der Rückruf von jquery ajax-Fehlern wird nicht aufgerufen.

Alexey Zakharov
quelle

Antworten:

46

Ich war kürzlich auch mit diesem Problem konfrontiert. Da Sie das Standardverhalten des Browsers beim Anzeigen des Popups im Falle einer 401( Basis- oder Digest- Authentifizierung) nicht ändern können , gibt es zwei Möglichkeiten, dies zu beheben:

  • Ändern Sie die Serverantwort so, dass a nicht zurückgegeben wird 401. Geben Sie 200stattdessen einen Code zurück und behandeln Sie diesen in Ihrem jQuery-Client.
  • Ändern Sie die Methode, die Sie für die Autorisierung verwenden, in einen benutzerdefinierten Wert in Ihrer Kopfzeile. Browser zeigen das Popup für Basic und Digest an . Sie müssen dies sowohl auf dem Client als auch auf dem Server ändern.

    headers : {
      "Authorization" : "BasicCustom"
    }

Bitte nehmen Sie auch einen Blick auf diese für ein Beispiel mit jQuery mit Basic - Auth.

nwinkler
quelle
10
WWW-Authentifizierung: xBasic Realm = com.example kann dies zusammen mit dem klassischen 401-Statuscode tun. Dieser Blog-Beitrag zeigte mir den Hinweis (ich bin nicht der Besitzer des Blogs ) oudvchar.blogspot.ca/2010/11/…
PM
2
@ PM, die Antwort des Blogs ist eine perfekte Lösung. Beachten Sie, dass Sie bei Verwendung <security:http-basic/>nicht definieren müssen, basicAuthenticationFiltersondern es definieren sollten als <security:http-basic entry-point-ref="myBasicAuthenticationEntryPoint"/>.
Brett Ryan
Können Sie mir bitte sagen, wie ich die Antwort überschreiben soll, bevor ich sie an den Client zurücksende? Ich verwende jaxrs mit grundlegender Authentifizierung. Welche Klasse muss ich überschreiben, um die Antwort zu ändern?
Mohammed Sameen
Aus irgendeinem Grund 401WWW-Authenticate:Bearer WWW-Authenticate:NTLM WWW-Authenticate:Negotiate
bekomme
34

Geben Sie einen generischen 400-Statuscode zurück und verarbeiten Sie diesen dann clientseitig.

Oder Sie können den 401 behalten und nicht den WWW-Authenticate-Header zurückgeben, auf den der Browser mit dem Authentifizierungs-Popup reagiert. Wenn der WWW-Authenticate-Header fehlt, fordert der Browser keine Anmeldeinformationen an.

Ibraheem
quelle
6
@MortenHaraldsen Nun, die 401-Antwort ist die richtige Antwort in diesem Fall. Das Problem ist, dass der Browser dies automatisch nativ verarbeitet, anstatt der Javascript-App zu erlauben, damit umzugehen. Sie können sich an den Standard halten, indem Sie nicht die vom Standard empfohlene Antwort zurückgeben, oder Sie können sich dafür entscheiden, sich nicht an den Standard zu halten, indem Sie den vom Standard empfohlenen Antwortcode zurückgeben.
Treffen
In meiner Express-App habe ich dies mit einer Zeile res.removeHeader('www-authenticate'); // prevents browser from popping up a basic auth window.
behoben
1
@Ibraheem, hätte es selbst nicht besser sagen können. Standards werden von Menschen geschaffen, die sich hinsetzen und reden, nicht unbedingt von denen, die sich hinsetzen und programmieren.
user2867288
16

Sie können das grundlegende Authentifizierungs-Popup mit einer Anforderungs-URL wie folgt unterdrücken:

https://username:[email protected]/admin/...

Wenn Sie einen 401-Fehler (falscher Benutzername oder falsches Passwort) erhalten, wird dieser mit dem Rückruf eines jquery-Fehlers korrekt behandelt. Es kann einige Sicherheitsprobleme verursachen (im Fall des http-Protokolls anstelle von https), aber es funktioniert.

UPD: Diese Lösungsunterstützung wird in Chrome 59 entfernt

Ivan Samovar
quelle
TOLLE!!!! Ich habe mein Problem gelöst, als das Problem 192.168.1.1 versuchte und der Router immer wieder nach Auth fragte.
Nadav Lebovitch
Wenn Sie in einem beliebigen Browser unter den Entwicklertools zur Registerkarte "Netzwerk" wechseln, können Sie den Benutzernamen und das Kennwort im Klartext lesen. Es funktioniert jedoch.
Bruno Finger
19
Tun Sie dies bitte niemals, die Anforderungsprotokolle auf Ihrem Webserver sind für mich jetzt viel wertvoller. Kostenlose Kombinationen aus Benutzernamen und Passwort sowie der Antwortcode! Danke
Remco
aber wie kann jemand verhindern, dass der Benutzername und das Passwort angezeigt werden
sdx11
3
Diese Authentifizierungsmethode wird immer schlechter und Chrome wird die Unterstützung für eingebettete Anmeldeinformationen, dh https://user:pass@host/in M59, um Juni 2017 einstellen. Weitere Informationen finden Sie in diesem Chromestatus-Blogbeitrag .
Garywoo
12

Wie andere bereits betont haben, besteht die einzige Möglichkeit, das Verhalten des Browsers zu ändern, darin, sicherzustellen, dass die Antwort entweder keinen 401-Statuscode enthält oder, falls dies der Fall ist, den WWW-Authenticate: BasicHeader nicht enthält . Da das Ändern des Statuscodes nicht sehr semantisch und unerwünscht ist, besteht ein guter Ansatz darin, den WWW-AuthenticateHeader zu entfernen . Wenn Sie Ihre Webserveranwendung nicht ändern können oder möchten, können Sie sie jederzeit über Apache bereitstellen oder als Proxy verwenden (wenn Sie Apache noch nicht verwenden).

Hier ist eine Konfiguration für Apache, um die Antwort neu zu schreiben, um den WWW-Authenticate-Header zu entfernen. IFF, den die Anforderung enthält, enthält den Header X-Requested-With: XMLHttpRequest(der standardmäßig von wichtigen Javascript-Frameworks wie JQuery / AngularJS usw. festgelegt wird) UND die Antwort enthält den Header WWW-Authenticate: Basic.

Getestet auf Apache 2.4 (nicht sicher, ob es mit 2.2 funktioniert). Dies hängt davon ab, welches mod_headersModul installiert wird. (Unter Debian / Ubuntu sudo a2enmod headersund Apache neu starten)

    <Location />
            # Make sure that if it is an XHR request,
            # we don't send back basic authentication header.
            # This is to prevent the browser from displaying a basic auth login dialog.
            Header unset WWW-Authenticate "expr=req('X-Requested-With') == 'XMLHttpRequest' && resp('WWW-Authenticate') =~ /^Basic/"
    </Location>   
syastrov
quelle
1
Um dasselbe mit Nginx zu tun, setzen Sieproxy_hide_header WWW-Authenticate;
Cuga
7

Verwenden Sie X-Requested-With: XMLHttpRequest mit Ihrem Anforderungsheader. Der Antwortheader enthält also nicht WWW-Authenticate: Basic.

beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', ("Basic "
                        .concat(btoa(key))));
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                },
sedhu
quelle
1
Das hatte für mich keine Wirkung. Welchen Servertyp verwenden Sie, an den die WWW-Authentifizierung nicht gesendet wird, wenn Sie XMLHttpRequest festlegen?
Robert Antonucci
@ RobertAntonucci es ist Apache Tomcat
Sedhu
5

Wenn Sie einen IIS-Server verwenden, können Sie IIS URL Rewriting (v2) einrichten, um den WWW-AuthenticationHeader Noneauf die angeforderte URL umzuschreiben .

Leitfaden hier .

Der Wert, den Sie ändern möchten, ist response_www_authenticate.

Wenn Sie weitere Informationen benötigen, fügen Sie einen Kommentar hinzu und ich werde die Datei web.config veröffentlichen.

Zymotik
quelle
1
Das hat super geklappt. Ich möchte darauf hinweisen, dass der Teil "Antwort" in URL Rewrite v2 unter IIS 7.5 als "RESPONSE_www_authenticate" geschrieben werden muss.
Michael Freeman
3

Wenn der WWW-Authenticate-Header entfernt wird, werden die Anmeldeinformationen nicht zwischengespeichert und der Autorisierungsheader wird nicht angefordert. Das bedeutet, dass Sie jetzt die Anmeldeinformationen für jede neue Anforderung eingeben müssen, die Sie generieren.

user2491441
quelle
Dies ist sehr wichtig, absolut genau richtig.
Tez Wingfield
2

Wenn Sie Ihre Serverantwort anpassen können, können Sie alternativ eine 403 Forbidden zurückgeben.

Der Browser öffnet das Authentifizierungs-Popup nicht und der jquery-Rückruf wird aufgerufen.

Javier Ferrero
quelle
5
Dies widerspricht der HTTP 1.1-Spezifikation, in der angegeben wird, dass "... die Autorisierung nicht hilft und die Anforderung NICHT wiederholt werden sollte".
Jukka Dahlbom
1
Es ist gültig, 403 zu erhalten, während Sie für Ressourcen authentifiziert werden, auf die Sie keinen Zugriff haben. 401 sollte gesendet werden, wenn Sie noch nicht authentifiziert wurden.
Brett Ryan
1

In Safari können Sie synchrone Anforderungen verwenden, um zu vermeiden, dass der Browser das Popup anzeigt. Natürlich sollten synchrone Anforderungen in diesem Fall nur zum Überprüfen der Benutzeranmeldeinformationen verwendet werden. Sie können eine solche Anforderung verwenden, bevor Sie die eigentliche Anforderung senden. Dies kann zu einer schlechten Benutzererfahrung führen, wenn der Inhalt (gesendet oder empfangen) sehr umfangreich ist.

    var xmlhttp=new XMLHttpRequest;
    xmlhttp.withCredentials=true;
    xmlhttp.open("POST",<YOUR UR>,false,username,password);
    xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
Emmanuel Sellier
quelle
In anderen Kontexten kann auch die Verwendung von "OPTIONEN" anstelle von "POST" hilfreich sein.
Emmanuel Sellier
0

Erstellen Sie eine / login-URL, und akzeptieren Sie dann die Parameter "Benutzer" und "Passwort" über GET. Sie benötigen keine grundlegende Authentifizierung. Verwenden Sie hier PHP, Node, Java, was auch immer und analysieren Sie Ihre passwd-Datei und stimmen Sie die Parameter (Benutzer / Pass) damit ab. Wenn eine Übereinstimmung vorliegt, leiten Sie sie an http: // user: [email protected]/ weiter (dies setzt die Anmeldeinformationen in Ihrem Browser fest). Wenn nicht, senden Sie eine 401-Antwort (ohne WWW-Authenticate-Header).

Neiker
quelle
Das wäre super für jeden, der versucht, Benutzernamen / Passwörter in den mittleren Angriffen aus dem Klartext-Mann herauszuspüren!
Ajax
0

Von der Rückseite mit Spring Boot habe ich benutzerdefinierten BasicAuthenticationEntryPoint verwendet:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().authorizeRequests()
            ...
            .antMatchers(PUBLIC_AUTH).permitAll()
            .and().httpBasic()
//    https://www.baeldung.com/spring-security-basic-authentication
            .authenticationEntryPoint(authBasicAuthenticationEntryPoint())
            ...

@Bean
public BasicAuthenticationEntryPoint authBasicAuthenticationEntryPoint() {
    return new BasicAuthenticationEntryPoint() {
        {
            setRealmName("pirsApp");
        }

        @Override
        public void commence
                (HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
                throws IOException, ServletException {
            if (request.getRequestURI().equals(PUBLIC_AUTH)) {
                response.sendError(HttpStatus.PRECONDITION_FAILED.value(), "Wrong credentials");
            } else {
                super.commence(request, response, authEx);
            }
        }
    };
}
Grigory Kislin
quelle