Problem description
We are running a Kibana 4.3 service. I do not want to modify the source code.
The objective is add an encrypted token, call it A-Token to every Ajax request that the browser makes to Kibana.
Background
The Kibana service is proxied by nginx.
When a user makes an Ajax request to the Kibana service, the request is intercepted by an nginx http_auth_request proxy and passed to an "auth" service that validates the token. If its missing or invalid, then "auth" returns 201 to http_auth_request and the request to the Kibana service is executed, else it returns a 404 and the request is denied since it was made without a valid token.
(this scheme is based on the encrypted token pattern often used as a countermeasure for cross-site scripting in session-less situations like the one at hand).
I read the W3 XMLHttpRequest documentation and it seems that setRequestHeader needs to run after open and before send - which implies that this scheme is either impossible in a general case or very JS platform dependent.
A test using the Jquery .ajaxSetup like this example, confirms that headers cannot be set independently:
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader(A-Token", 1314159);
}
});
Looking for possible solutions which will not require forking Kibana.
Danny
I was searching for solution for this problem as well but couldn't find anything and then I came up with next solution:
XMLHttpRequest.prototype.origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
this.origOpen.apply(this, arguments);
this.setRequestHeader('X-TOKEN', 'the token');
};
Related
I've searched the netlify docs and I can't figure this out.
I have a serverless function located here
/.netlify/functions/orderCreate
But I can hit this in my browser or with curl and it tries to create an order. If an attacker finds out about this function they could create thousands fake orders in my db.
I know I can do some simple checks like make sure it is a HTTP post, or make sure it has some valid session ID but I would really like some type of auth or better security.
Because all requests should come from the a client side react app via an ajax request can I limit it to the same domain or something ?
As Netlify doesn't provide a way to check and specific requests based on origin, you could do it manually from inside your function's code and send a 403 response if the Origin isn't your client-side domain:
exports.handler = function(event, context, callback) {
if (event.headers["Origin"] !== "https://whateverisyourdomainname.netlify.com")
return callback(null, { status: 403 })
// else, do whatever your function does
}
Recent browsers do prevent a user from setting the Origin header himself. However, nothing prevents anyone to craft a curl request and to spoof the Origin header to hit your function. If you wish to really prevent it, you should set-up a proper authentication process to your application.
I am currently working on an problem with a login page for an AngularJS app. The login page uses the $http service to submit the username and password using Basic authentication (Authorization: Basic (username and password in base 64)) to a Web service that may or may not be running on the same server that the webapp is hosted on. If authentication succeeds, the server returns a response with status 200 OK; otherwise, it returns a 401 Not Authorized. We have an error function to gracefully handle this error condition, but before it is even called, the browser by default shows a modal dialog for the user to enter his or her username and password. How can I prevent this?
I've looked at several sources, including the W3 standards for XHR.send(), for help, and my findings show that in Firefox and Chrome, the browser dialog pops up after a 401 response to an XHR call when all of the following are true:
1) The request is "same-origin" (which it is in the cases where the web service is running on the same server that serves the webapp)
2) The response includes the header WWW-Authenticate: Basic [some realm] or WWW-Authenticate: Digest [some realm] (our web service returns the former)
3) The request was not made by specifically setting a username and password in the XHR object whose send() method was called.
I found a test site (which SO won't let me link to) that exhibits the desired behavior for 401 responses (no modal login box). It meets the first two conditions but avoids meeting the third, apparently because it sets the XHR object's username and password by sending them as arguments #4 and 5 to its open() function. I'm not sure if there's any other way to set these properties of the XHR object, since I can't even find them by inspecting the XHR object in a browser's JavaScript debugger.
The problem is that our site's login service doesn't itself call XmlHttpRequest.open() to pass the username and password; instead, it creates the Authorization header itself and passes it in the headers collection of a params object to $http. By inspecting the source of angular.js, I found that $http then proceeds to call open() with only three parameters.
Does Angular provide a way to have $http call the 5-parameter overload of open(), or otherwise prevent this login dialog from showing up? If not, I can only think of a few workarounds:
1) Somehow decorate $http to enforce calling the 5-parameter overload of open() if a username and password are provided
2) Somehow use $httpBackend to achieve the same as #1 (though the documentation discourages developers from using $httpBackend so I'm not sure if this is a good idea or even possible)
3) Ignore $http and have my login service create and send the XHR itself
4) Alter the server so it doesn't return the WWW-Authenticate: Basic header (least desirable)
Is there a well-known or "right" way to work around this problem?
The issues you are facing is due to the first reason you have specified
1) The request is "same-origin" (which it is in the cases where the web service is running on the same server that serves the webapp).
solution
Either add access-control-allow-origin header to your backend service in order to acccept calls from different origin.
or
if you are in development phase and later your frontend and service are anyway going to be in same origin,then use https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en extension ,
this will allow you to override chrome cross origin policy (this is just for development,its a workaround).
or
Open chrome with web security disabled by opening chrome from command prompt
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
I use the jQuery ajax functions to access a web service, but the server, instead of returning a response with a status code describing a problem, the request is redirected to a page with a 200 header, describing the problem. I can't make any changes to this, so I need to solve it on the client somehow.
Example:
A request goes to some URL which is not found, so I receive a 302 Redirect to another location. A new request is sent, and I receive a 200 OK, thus preventing the error callback to fire.
Is there some way I can prevent the ajax request to follow redirects and instead invoke a callback, preferably the error method. Alternatively, is it possible to detect if a redirect has happened in the client?
I find your question interesting, but the problem in whole seems me more a misunderstanding. At least I'll try to explain my understanding of the problem.
The silent (transparent) redirection is the part of XMLHttpRequest specification (see here especially the words "... transparently follow the redirect ..."). The standard mention only that the user agent (the web browser) can prevent or notify of certain kinds of automatic redirections, but it's not a part of XMLHttpRequest. It's the part of HTTP client configuration (OS configuration) or the web browser configuration. So jQuery.ajax can't have any option where you can prevent redirection.
You can see that HTTP redirection is the part of HTTP protocol and not a part of XMLHttpRequest. So it's on the another level of abstraction or the network stack. For example the data from the XMLHttpRequest can be retrieved from the HTTP proxy or from the local browser cache, and it's the part of HTTP protocol. Mostly the server which provide the data and not the client can influence on caching.
You can compare the requirement from your question with the requirement to prevent changing of IP address of the web server or the changing of the IP route during the communication. All the things can be interesting in some scenarios, but there are parts of another level of the communication stack and can't be managed by jQuery.ajax or XMLHttpRequest.
The XMLHttpRequest standard say that the client configuration can have options which prevent redirection. In case of "Microsoft world", which I better know, you can look at WinHttpSetOption function which can be used to set WINHTTP_OPTION_DISABLE_FEATURE option with the WINHTTP_DISABLE_REDIRECTS value. Another way are the usage of WINHTTP_OPTION_REDIRECT_POLICY option with the WINHTTP_OPTION_REDIRECT_POLICY_NEVER value. One more feature which one can use in Windows is the WinHttpSetStatusCallback function which can set callback function received some notifications like WINHTTP_CALLBACK_FLAG_REDIRECT.
So it's do possible to implement your requirements in general, but the solution will be probably not independent from the operation system or the web browser and be not on the level of jQuery.ajax or XMLHttpRequest.
I don't believe it is possible. The underlying library (XHR) makes the new request transparently. That being said, what I have done in these situations (usually a session-timeout type of deal that takes me to a login page) is send back a custom response header. I also have setup a global ajax handler that checks for the presence of that header, and responds appropriately when present (for example, redirecting the whole page to the login screen).
In case you're interested, here's the jQuery code I have to watch for that custom header:
/* redirects main window when AJAX request indicates that the session has expired on the backend. */
function checkSession(event, xhr, ajaxOptions)
{
if (xhr.readyState == 4)
{
if(xhr.getResponseHeader("Login-Screen") != null && xhr.getResponseHeader("Login-Screen").length)
{
window.location.href='sessionExpired.html'; //whatever
}
}
}
$(document).ajaxComplete(checkSession)
I found a feature to check if your call has been redirected. It's xhr.state(): if it's "rejected" then a redirection happened.
Example with success callback:
request.success(function(data, textStatus, xhr)
{
if(xhr.state() == "resolved")
{
//no redirection
}
if(xhr.state() == "rejected")
{
//redirection
}
});
Example with error callback:
request.error(function(xhr, textStatus)
{
if (xhr.state() == "rejected")
{
//redirection
location.href = "loginpage";
} else
{
//some other error happened
alert("error");
}
});
I can't possibly add to the insightful wisdom of the previous coders who've responded, but I will add a specific case that others may find useful to know about.
I came across this 302 silent redirect in the context of SharePoint. I have some simple Javascript client code that pings a SharePoint sub-site, and if it receives a 200 HTTP response, it relocates to that site, via window.location. If it receives anything else, it gives the user a notice that the site doesn't exist.
However, in the case where the site exists but the user does not have permission, SharePoint silently redirects to an AccessDenied.aspx page. SharePoint has already done the HTTP 401 authentication handshake at the server/farm level - the user has access to SharePoint. But the access to the sub-site is handled I suppose using database flags of some sort. The silent redirect bypasses my "else" clause, so I can't throw up my own error. In my case, this is not a show-stopper - it is consistent predictable behavior. But it was a little surprising, and I learned something about HTTP requests in the process!
I was interested in the same thing and could not find the state() method mentioned by Takman and did a little digging for myself. For the sake of people turning up here in search of an answer, here are my findings:
As stated multiple times, you cannot prevent redirects, but you can detect them. According to MDN you can use the responseURL of the XMLHttpRequestObject, which will contain the final URL the response came from, after all redirects. Only caveat is that it is not supported by Internet Explorer (Edge has it). Since the xhr/jqXHR passed into the success/done function of jquery is an extension of the actual XMLHttpRequest, it should be available there, too.
While it is not possible to disable location redirect following in XmlHttpRequests, it is when using fetch():
fetch('url', {redirect: manual});
I suppose you receive a 200 response because the second time there is no redirection, because the 404 page does not expire, it is saved in the cache. That is to say that the second time the browser gives you the page in the cache.
There is a property "cache" in the ajax jquery.
http://api.jquery.com/jQuery.ajax/
You should write it to "false"
I'm not sure if this will apply in your case, but you can write code to respond to specific status codes in AJAX function -
$.ajax({
url: '/admin/secret/data',
type: 'POST',
contentType: 'application/json; charset=utf-8',
statusCode: {
200: function (data) {
alert('302: Occurred');
// Bind the JSON data to the UI
},
401: function (data) {
alert('401: Occurred');
// Handle the 401 error here.
}
}
});
In the request headers in the case of ajax request you will have the following
X-Requested-With XMLHttpRequest
By this criteria on the server side you can filter requests.
I'm getting the following exception while making a call using XMLHttp object asynchronously in Mozilla Firefox.
407 Proxy Authentication Required
The ISA Server requires authorization to fulfill the request.
Access to the Web Proxy filter is denied.
Description of cause:
Actually I'm trying to make an asynchronous request to using get in javascript. It is working fine using IE 6 but for IE 7 and Firefox 3.5, it will it won't get any data using asynchronous request so how to overcome this problem?
When I debug in Firefox 3.5 using firebug it shows
407 Proxy Authentication Required The ISA Server requires authorization to fulfil the request. Access to the Web Proxy filter is denied.
exception at console so how to tackle this issue
Note: our network has proxy server
I recognize I am a little late to the party here, and this question, however, I was having the exact same problem. #FK82 indicated the right solution and I wanted to document it, as I've tried it and it works.
$.ajax({
url: "http://somefancyurl.com/api/do_it",
data: { id:"user" },
dataType: "jsonp",
success: function(data) {
console.log(data);
}
});
If I do not specify jsonp I get the 407 Proxy Authentication Required error.
Although the original question didn't specify JQuery, I was able to test successfully with FireFox 3.6.x, and IE7 using this approach & JSONP.
Proxy Authentication is simply an existence of a http header field called "Proxy-Authorization"
Browsers are supposed to send those stuff automatically.
But since you could add some custom header to ajax requests, you could try setting it manually.
request.setRequestHeader("Proxy-Authorization", value);
request is the XMLHttp object
value is the base64 encoded version of username:password
Note that I am not sure thats the case or not, correct me if I am wrong.
Or some page I found on google says to add X-Requested-With, may be worth to try that too.
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
I know this is a long shot, but I figured I'd ask the question anyway.
I have an HTTPS page and am dynamically creating a form. I want to POST the form to an HTTP page. Is this possible without the browser popping up a warning? When I do this on IE8, I get the following message:
Do you want to view only the webpage content that was delivered securely?
Essentially, I'm asking about the inverse of question 1554237.
Sadly, I know of absolutely no way to not get warned when posting from HTTPS to HTTP. If you serve the form securely, the browser expects to submit the data securely as well. It would surprise the user if anything else was possible.
Nope, can't be done. Our good friend IE will always pop up that warning.
There is a way to do this if you write a back-end service of your own. So lets say you want to post an HTTP request to s1 using your front-end service fs1.
If you use Spring, you can use an ajax call from fs1 to a 'uri' that is recognized by your spring back-end, say bs1. Now, the service bs1 can make the call to the s1.
Pictorial representation here: http://i.stack.imgur.com/2lTxL.png
code:
$.ajax
({
type: "POST",
uri:/json/<methodName>
data: $('#Form').serialize(),
success: function(response)
{
//handle success here
},
error: function (errorResponse)
{
//handle failure here
}
})
You can solve this by either acting as a proxy for the form destination yourself (i.e. let the form submit to your server which in turn fires a normal HTTP request and returns the response), or to let access the page with the form by HTTP only.
If you don't need to actually redirect to the insecure page, you can provide a web service (authenticated) that fires off the request for you and returns the data.
For example:
From the authenticated page, you call doInsecure.action which you create as a web service over https. doInsecure.action then makes a manual POST request to the insecure page and outputs the response data.
You should be able to do this with the opensource project Forge, but it sounds like overkill. The Forge project provides a JavaScript interface (and XmlHttpRequest wrapper) that can do cross-domain requests. The underlying implementation uses Flash to enable cross-domain (including http <=> https) communication.
http://github.com/digitalbazaar/forge/blob/master/README
So you would load the Forge JavaScript and swf from your server over https and then do a Forge-based XmlHttpRequest over http to do the POST. This would save you from having to do any proxy work on the server, but again, it may be more work than just supporting the POST over https. Also, the assumption here is that there's nothing confidential in the form that is being posted.