브라우저가 기본 인증 팝업을 호출하고 Jquery를 사용하여 401 오류를 처리하는 것을 방지하는 방법은 무엇입니까?


107

기본 인증을 사용하여 인증 요청을 보내야합니다. jquery를 사용하여 성공적으로 구현했습니다. 그러나 401 오류가 발생하면 기본 인증 브라우저 팝업이 열리고 jquery ajax 오류 콜백이 호출되지 않습니다.


답변:


46

나도 최근에이 문제에 직면했다. 401( 기본 또는 다이제스트 인증)의 경우 팝업을 표시하는 브라우저의 기본 동작을 변경할 수 없기 때문에이 문제를 해결하는 두 가지 방법이 있습니다.

  • 를 반환하지 않도록 서버 응답을 변경합니다 401. 반환200대신 코드를 jQuery 클라이언트에서 처리하십시오.
  • 인증에 사용하는 방법을 헤더의 사용자 지정 값으로 변경합니다. 브라우저는 기본다이제스트에 대한 팝업을 표시합니다 . 클라이언트와 서버 모두에서이를 변경해야합니다.

    headers : {
      "Authorization" : "BasicCustom"
    }

도 살펴 보시기 바랍니다 기본 인증과 jQuery를 사용하는 예를 들어.


10
WWW-Authenticate : xBasic realm = com.example은 클래식 401 상태 코드와 함께이를 수행 할 수 있습니다. 이 블로그 포스트는 나에게 힌트를 보여 주었다 (나는 블로그의 소유자가 아니다) loudvchar.blogspot.ca/2010/11/…
PM

2
@PM, 블로그의 답변은 완벽한 솔루션입니다. 를 사용하는 경우 <security:http-basic/>정의 할 필요는 basicAuthenticationFilter없지만 <security:http-basic entry-point-ref="myBasicAuthenticationEntryPoint"/>.
브렛 라이언

클라이언트로 다시 보내기 전에 응답을 재정의하는 방법을 알려 주실 수 있습니까? 기본 인증으로 jaxrs를 사용하고 있습니다. 응답을 수정하려면 어떤 클래스를 재정의해야합니까?
mohammed sameen

어떤 이유로 나는 반환 팝업 무엇입니까 401WWW-Authenticate:Bearer WWW-Authenticate:NTLM WWW-Authenticate:Negotiate음주 당신이 될 것이라고 이유를 알고
DevEng

34

일반 400 상태 코드를 반환 한 다음 해당 클라이언트 측을 처리합니다.

또는 401을 유지하고 WWW-Authenticate 헤더를 반환하지 않을 수 있습니다. 실제로 브라우저가 인증 팝업으로 응답하는 것입니다. WWW-Authenticate 헤더가없는 경우 브라우저는 자격 증명을 요구하지 않습니다.


6
@MortenHaraldsen 글쎄요 401 응답은이 경우에 적절한 응답입니다. 문제는 브라우저가 자바 스크립트 앱이이를 처리하도록 허용하는 대신 기본적으로이를 자동으로 처리한다는 것입니다. 표준이 권장하는 적절한 응답을 반환하지 않음으로써 표준을 고수하거나 표준 권장 응답 코드를 반환하여 표준을 고수하지 않도록 선택할 수 있습니다. 선택하세요 :)
Ibraheem

내 익스프레스 앱에서이 문제를 한 줄로 수정했습니다. res.removeHeader('www-authenticate'); // prevents browser from popping up a basic auth window.
gstroup

1
@Ibraheem, 더 나은 나 자신을 말할 수 없었습니다. 표준은 앉아서 코딩하는 사람이 아니라 앉아서 말하는 사람에 의해 만들어집니다.
user2867288

15

다음과 같은 요청 URL로 기본 인증 팝업을 억제 할 수 있습니다.

https://username:password@example.com/admin/...

401 오류 (잘못된 사용자 이름 또는 암호)가 발생하면 jquery 오류 콜백으로 올바르게 처리됩니다. 일부 보안 문제를 일으킬 수 있지만 (https 대신 http 프로토콜의 경우) 작동합니다.

UPD : 이 솔루션 지원은 Chrome 59에서 제거됩니다.


놀랄 만한!!!! 문제가 192.168.1.1을 시도하고 라우터가 계속 인증을 요청했기 때문에 내 문제를 해결했습니다.
Nadav Lebovitch 2015

개발자 도구 아래의 "네트워크"탭으로 이동하면 모든 브라우저에서 일반 텍스트로 사용자 이름과 비밀번호를 읽을 수 있습니다. 그래도 작동합니다.
Bruno Finger

19
제발 이렇게하지 마십시오. 웹 서버의 요청 로그는 지금 나에게 훨씬 더 가치가 있습니다. 무료 사용자 이름과 암호 콤보와 응답 코드! 감사합니다
Remco의

그러나 누군가가 사용자 이름과 암호가 보이지 않게하려면 어떻게해야
합니까?

3
이 인증 방법은 더 이상 사용되지 않으며 Chrome은 https://user:pass@host/2017 년 6 월경 M59에서 포함 된 자격 증명에 대한 지원을 중단 할 예정입니다 . 자세한 내용은 이 chromestatus 블로그 게시물 을 참조하세요.
Garywoo 2017-04-26

13

다른 사람들이 지적했듯이 브라우저의 동작을 변경하는 유일한 방법은 응답에 401 상태 코드가 포함되지 않았는지 또는 포함 된 경우 WWW-Authenticate: Basic헤더를 포함하지 않는지 확인하는 것 입니다. 상태 코드를 변경하는 것은 그다지 의미가없고 바람직하지 않으므로 WWW-Authenticate헤더 를 제거하는 것이 좋습니다 . 웹 서버 애플리케이션을 수정할 수 없거나 수정할 수없는 경우 언제든지 Apache를 통해 제공하거나 프록시 할 수 있습니다 (아파치를 아직 사용하지 않는 경우).

다음은 요청에 포함 된 WWW-Authenticate 헤더 IFF를 제거하기 위해 응답을 다시 작성하는 Apache의 구성입니다 X-Requested-With: XMLHttpRequest(JQuery / AngularJS 등의 주요 Javascript 프레임 워크에서 기본적으로 설정 됨). 헤더 WWW-Authenticate: Basic.

Apache 2.4에서 테스트되었습니다 (2.2에서 작동하는지 확실하지 않음). 이것은 mod_headers설치 되는 모듈에 의존합니다 . (Debian / Ubuntu에서 sudo a2enmod headersApache 다시 시작)

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

1
Nginx와 동일하게하려면 설정proxy_hide_header WWW-Authenticate;
Cuga

7

X-Requested-With : XMLHttpRequest를 요청 헤더와 함께 사용하십시오. 따라서 응답 헤더에는 WWW-Authenticate : Basic이 포함되지 않습니다.

beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', ("Basic "
                        .concat(btoa(key))));
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                },

1
그것은 나에게 효과가 없었습니다. XMLHttpRequest를 설정할 때 WWW-Authenticate가 전송되지 않는 서버 유형은 무엇입니까?
Robert Antonucci

@RobertAntonucci은 아파치 톰캣
sedhu

5

IIS 서버를 사용하는 경우 IIS URL 다시 쓰기 (v2) WWW-AuthenticationNone설정하여 요청 된 URL에 헤더를 다시 쓸 수 있습니다.

여기에서 안내하십시오 .

변경하려는 값은 response_www_authenticate입니다.

더 많은 정보가 필요한 경우 의견을 추가하면 web.config 파일을 게시하겠습니다.


1
이것은 훌륭하게 작동했습니다. IIS 7.5의 URL Rewrite v2에서 "응답"부분은 "RESPONSE_www_authenticate"로 작성되어야합니다.
Michael Freeman

3

WWW-Authenticate 헤더가 제거되면 자격 증명 캐싱을 얻지 못하고 요청에서 Authorization 헤더를 반환하지 않습니다. 즉, 이제 생성하는 모든 새 요청에 대해 자격 증명을 입력해야합니다.


이것은 매우 중요합니다.
Tez Wingfield 2017

2

또는 서버 응답을 사용자 정의 할 수있는 경우 403 Forbidden을 반환 할 수 있습니다.

브라우저는 인증 팝업을 열지 않고 jquery 콜백이 호출됩니다.


5
이는 HTTP 1.1 사양에 위배됩니다. 여기서 "... 인증은 도움이되지 않으며 요청은 반복되지 않아야합니다."라고 명시되어 있습니다.
Jukka Dahlbom 2013

1
액세스가 허용되지 않은 리소스에 대해 인증되는 동안 403을 수신하는 것은 유효하며, 아직 인증되지 않은 곳에 401을 전송해야합니다.
브렛 라이언

1

Safari에서는 브라우저가 팝업을 표시하지 않도록 동기 요청을 사용할 수 있습니다. 물론이 경우 동기 요청은 사용자 자격 증명을 확인하는 데만 사용해야합니다. 실제 요청을 보내기 전에 이러한 요청을 사용하면 콘텐츠 (전송 또는 수신)가 상당히 많은 경우 나쁜 사용자 경험을 유발할 수 있습니다.

    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');

다른 상황에서는 "POST"대신 "OPTIONS"를 사용하는 것도 도움이 될 수 있습니다.
Emmanuel Sellier

0

GET을 통해 "user"및 "password"매개 변수를 허용하고 기본 인증이 필요하지 않은 것보다 / login URL을 만드십시오. 여기에서 php, node, java 등을 사용하고 passwd 파일을 구문 분석하고 매개 변수 (user / pass)를 일치시킵니다. 일치하는 항목이 있으면 http : // user : pass@domain.com/ (브라우저에 자격 증명이 설정 됨) 로 리디렉션하고 그렇지 않은 경우 401 응답을 보냅니다 (WWW-Authenticate 헤더 없음).


중간에있는 일반 텍스트 공격에서 사용자 이름 / 비밀번호를 알아 내려는 모든 사람에게 매우 유용합니다!
Ajax

0

Spring Boot의 뒷면에서 사용자 지정 BasicAuthenticationEntryPoint를 사용했습니다.

@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);
            }
        }
    };
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.