programing tip

안전하지 않은 응답 또는 연결 거부로 인해 Ajax 호출이 실패했는지 판별

itbloger 2020. 7. 24. 07:50
반응형

안전하지 않은 응답 또는 연결 거부로 인해 Ajax 호출이 실패했는지 판별


나는 많은 연구를 해왔고 이것을 처리하는 방법을 찾지 못했습니다. https 서버에서 사용자 정의 자체 서명 인증서로 부두를 실행하는 locahost https 서버로 jQuery ajax 호출을 수행하려고합니다. 내 문제는 (인증서 승인이 없기 때문에) 응답이 연결 거부인지 또는 안전하지 않은 응답인지 여부를 확인할 수 없다는 것입니다. 두 시나리오의 차이점을 결정하는 방법이 있습니까? responseText, 그리고 statusCode크롬 콘솔에서 나는 차이를 볼 수 있지만, 항상 두 경우 모두 동일합니다 :

net::ERR_INSECURE_RESPONSE
net::ERR_CONNECTION_REFUSED

responseTextstatusCode두 경우 모두 항상 ""이고 항상 "0"입니다.

내 질문은 jQuery ajax 호출이 실패했는지 ERR_INSECURE_RESPONSE또는 실패했는지 어떻게 알 수 ERR_CONNECTION_REFUSED있습니까?

인증서가 수락되면 모든 것이 잘 작동하지만 로컬 호스트 서버가 종료되었는지 또는 실행 중이지만 인증서가 아직 수락되지 않았는지 알고 싶습니다.

$.ajax({
    type: 'GET',
    url: "https://localhost/custom/server/",
    dataType: "json",
    async: true,
    success: function (response) {
        //do something
    },
    error: function (xhr, textStatus, errorThrown) {
        console.log(xhr, textStatus, errorThrown); //always the same for refused and insecure responses.
    }
});

여기에 이미지 설명을 입력하십시오

수동으로 요청을 수행해도 동일한 결과가 나타납니다.

var request = new XMLHttpRequest();
request.open('GET', "https://localhost/custom/server/", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

최신 웹 브라우저와 구별 할 수있는 방법이 없습니다.

W3C 사양 :

아래 단계는 간단한 교차 출처 요청에 대해 사용자 에이전트가 수행해야하는 작업을 설명합니다 .

요청 단계를 적용하고 요청하는 동안 아래 요청 규칙을 준수하십시오.

수동 리디렉션 플래그가 설정되어 있지 않고 응답의 HTTP 상태 코드가 301, 302, 303, 307 또는 308 인 경우 리디렉션 단계를 적용하십시오.

최종 사용자가 요청을 취소 한 경우 중단 단계를 적용하십시오.

네트워크 오류가있는 경우 DNS 오류, TLS 협상 실패 또는 기타 유형의 네트워크 오류가 발생하면 네트워크 오류 단계를 적용 하십시오 . 어떤 종류의 최종 사용자 상호 작용도 요청하지 마십시오.

참고 : 여기에는 HTTP 상태 코드 410과 같은 일부 유형의 오류를 나타내는 HTTP 응답이 포함되지 않습니다.

그렇지 않으면 리소스 공유 확인을 수행하십시오. 실패가 리턴되면 네트워크 오류 단계를 적용하십시오. 그렇지 않으면 전달이 리턴되면이 알고리즘을 종료하고 교차 출처 요청 상태를 성공으로 설정하십시오. 실제로 요청을 종료하지 마십시오.

읽을 수 있듯이 네트워크 오류에는 오류가 포함 된 HTTP 응답이 포함되지 않으므로 상태 코드는 항상 0이고 오류는 ""입니다.

출처


참고 : 다음 예제는 Chrome 버전 43.0.2357.130을 사용하고 OP 버전을 에뮬레이트하기 위해 만든 환경에 대해 작성되었습니다. 설정 된 코드는 답변의 맨 아래에 있습니다.


나는이 접근 방식이 HTTPS 대신 HTTP를 통해 보조 요청을하는 접근법이라고 생각하지만 이 답변 은 최신 버전의 브라우저가 혼합 된 콘텐츠를 차단하기 때문에 불가능하다는 것을 기억했습니다.

이는 HTTPS를 사용하거나 그 반대의 경우 웹 브라우저가 HTTP를 통한 요청을 허용하지 않음을 의미합니다.

이것은 몇 년 전부터 이와 같았지만 Mozilla Firefox와 같은 이전 웹 브라우저 버전에서는 23 버전이 허용됩니다.

그것에 대한 증거 :

HTTPS usign Web Broser 콘솔에서 HTTP 요청하기

var request = new XMLHttpRequest();
request.open('GET', "http://localhost:8001", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

다음과 같은 오류가 발생합니다.

Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://localhost:8001/'. This request has been blocked; the content must be served over HTTPS.

Same error will appear in the browser console if you try to do this in other ways as adding an Iframe.

<iframe src="http://localhost:8001"></iframe>

Using Socket connection was also Posted as an answer, I was pretty sure that the result will be the same / similar but I've give it a try.

Trying to Open a socket connection from the Web Broswer using HTTPS to a non Secure socket endpoint will end in mixed content errors.

new WebSocket("ws://localhost:8001", "protocolOne");

1) Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://localhost:8001/'. This request has been blocked; this endpoint must be available over WSS.

2) Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

Then I've tried to connect to a wss endpoint too see If I could read some information about network connection errors:

var exampleSocket = new WebSocket("wss://localhost:8001", "protocolOne");
exampleSocket.onerror = function(e) {
    console.log(e);
}

Executing snippet above with Server turned off results in:

WebSocket connection to 'wss://localhost:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

Executing snippet above with Server turned On

WebSocket connection to 'wss://localhost:8001/' failed: WebSocket opening handshake was canceled

But again, the error that the "onerror function" output to the console have not any tip to differentiate one error of the other.


Using a proxy as this answer suggest could work but only if the "target" server has public access.

This was not the case here, so trying to implement a proxy in this scenario will lead Us to the same problem.

Code to create Node.js HTTPS server:

I've created two Nodejs HTTPS servers, that use self signed certificates:

targetServer.js:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs2/key.pem'),
    cert: fs.readFileSync('./certs2/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8001);

applicationServer.js:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs/key.pem'),
    cert: fs.readFileSync('./certs/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8000);

To make it work you need to have Nodejs Installed, Need to generate separated certificates for each server and store it in the folders certs and certs2 accordingly.

To Run it just execute node applicationServer.js and node targetServer.js in a terminal (ubuntu example).


As of now: There is no way to differentiate this event between browers. As the browsers do not provide an event for developers to access. (July 2015)

This answer merely seeks to provide ideas for a potential, albiet hacky and incomplete, solution.


Disclaimer: this answer is incomplete as it doesn't completely solve OP's issues (due to cross-origin policies). However the idea itself does has some merit that is further expanded upon by: @artur grzesiak here, using a proxy and ajax.


After quite a bit of research myself, there doesn't seem to be any form of error checking for the difference between connection refused and an insecure response, at least as far as javascript providing a response for the difference between the two.

The general consensus of my research being that SSL certificates are handled by the browser, so until a self-signed certificate is accepted by the user, the browser locks down all requests, including those for a status code. The browser could (if coded to) send back it's own status code for an insecure response, but that doesn't really help anything, and even then, you'd have issues with browser compatibility (chrome/firefox/IE having different standards... once again)

Since your original question was for checking the status of your server between being up versus having an unaccepted certificate, could you not make a standard HTTP request like so?

isUp = false;
isAccepted = false;

var isUpRequest = new XMLHttpRequest();
isUpRequest.open('GET', "http://localhost/custom/server/", true); //note non-ssl port
isUpRequest.onload = function() {
    isUp = true;
    var isAcceptedRequest = new XMLHttpRequest();
    isAcceptedRequest.open('GET', "https://localhost/custom/server/", true); //note ssl port
    isAcceptedRequest.onload = function() {
        console.log("Server is up and certificate accepted");
        isAccepted = true;
    }
    isAcceptedRequest.onerror = function() {
        console.log("Server is up and certificate is not accepted");
    }
    isAcceptedRequest.send();
};
isUpRequest.onerror = function() {
    console.log("Server is down");
};
isUpRequest.send();

Granted this does require an extra request to verify server connectivity, but it should get the job done by process of elimination. Still feels hacky though, and I'm not a big fan of the doubled request.


@Schultzie's answer is pretty close, but clearly http - in general - will not work from https in the browser environment.

What you can do though is to use an intermediate server (proxy) to make the request on your behalf. The proxy should allow either to forward http request from https origin or to load content from self-signed origins.

Having your own server with proper certificate is probably an overkill in your case -- as you could use this setting instead of the machine with self-signed certificate -- but there is a plenty of anonymous open proxy services out there.

So two approaches that come to my mind are:

  1. ajax request -- in such a case the proxy has to use appropriate CORS settings
  2. use of an iframe -- you load your script (probably wrapped in html) inside an iframe via the proxy. Once the script loaded it sends a message to its .parentWindow. If your window received a message you can be sure the server is running (or more precisely was running a fraction of second before).

If you are only interested in your local environment you can try to run chrome with --disable-web-security flag.


Another suggestion: did you try to load an image programatically to find out if more info is present there?


Check out jQuery.ajaxError() Taken reference from : jQuery AJAX Error Handling (HTTP Status Codes) It catches global Ajax errors which you can handle in any number of ways over HTTP or HTTPS:

if (jqXHR.status == 501) {
//insecure response
} else if (jqXHR.status == 102) {
//connection refused
}

Unfortunately the present-day browser XHR API does not provide an explicit indication for when the browser refuses to connect due to an "insecure response", and also when it does not trust the website's HTTP/SSL certificate.

But there are ways around this problem.

One solution I came up with to determine when the browser does not trust the HTTP/SSL certificate, is to first detect if an XHR error has occurred (using the jQuery error() callback for instance), then check if the XHR call is to an 'https://' URL, and then check if the XHR readyState is 0, which means that the XHR connection has not even been opened (which is what happens when the browser does not like the certificate).

Here's the code where I do this: https://github.com/maratbn/RainbowPayPress/blob/e9e9472a36ced747a0f9e5ca9fa7d96959aeaf8a/rainbowpaypress/js/le_requirejs/public/model_info__transaction_details.js#L88


나는 현재 이러한 오류 메시지를 감지하는 방법이 없다고 생각하지만, 할 수있는 해킹은 응용 프로그램 서버 앞에서 nginx와 같은 서버를 사용하는 것입니다. 따라서 응용 프로그램 서버가 다운되면 나빠질 것입니다 502JS에서 감지 할 수있는 상태 코드가있는 nginx의 게이트웨이 오류 . 그렇지 않으면 인증서가 유효하지 않은 경우에도와 동일한 일반 오류가 발생합니다 statusCode = 0.

참고 URL : https://stackoverflow.com/questions/31058764/determine-if-ajax-call-failed-due-to-insecure-response-or-connection-refused

반응형