AJAX request doesn't send Cookies set from same domain - javascript

I'm developing a sort of user-tracking system, that works as follows:
1) A webmaster adds a js script in his website:
<script src="http://example.com/in/tracking.js"></script>
2) When a user loads the page, the javascript request send back a cookie in response:
Set-Cookie:trackid=c1d7fde9cf87a9501cea57cedde97998;Version=1;Comment=;Domain=example.com;Path=/;Max-Age=31556926
(it's basically a simple cookie that lasts for 1 year)
3) The tracking.js makes a POST XMLHttpRequest, to the same example.com domain, passing some parameters:
theAjaxRequest.open("POST","http://example.com/in",true);
theAjaxRequest.setRequestHeader("Content-type", "multipart/form-data");
theAjaxRequest.send(parameters);
4) The backend of example.com should then read the previously set "trackid" cookie, but, instead, I get no cookies on request... By analyzing the POST request via Chrome inspector, I noted that no cookies are passed in request headers (while the first GET request for tracking.js sets correctly the cookie via Set-Cookie).
How come? At first I assumed it may be a problem related to same-origin-policy; so I enabled CORS headers on back-end web server. No results. So, I tried to load tracking.js on a website under same domain of example.com (say web.example.com). Anyway, no results again...
Am I missing something?

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
Line 7 shows the flag on XMLHttpRequest that has to be set in order to make the invocation with Cookies, namely the withCredentials boolean value. By default, the invocation is made without Cookies. Since this is a simple GET request, it is not preflighted, but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header, and not make the response available to the invoking web content.

Related

XMLHttpRequest causes two network events

I'm noticing when I have use a XMLHttpRequest in my script, that for each time it gets called two events appear in Chrome's network waterfall.
The first event has a type xhr and a size of around ~27bytes and the second event has a type of text/html and a size of 0bytes.
I've noticed it in the past and have looked over it, but now I'm noticing its causing the page it connects to for it to run twice.
Is this normal? Did I implement something incorrectly?
function example(){
console.log('ran'); // this shows the function only ran once
var form = new FormData(), xml = new XMLHttpRequest();
form.append('test', '...');
xml.upload.onprogress = function(e){something.style.width = (e.loaded*100/e.total) + "%";}
xml.onload = function(){alert('done');}
xml.open('POST', 'https://externaldomainexample.net', true);
xml.send(form);
}
The two requests are being made because you are making a request to a different domain from which your page is hosted (cross origin). If you enable the "method" column in Chrome's network tab you'll see that the first request is an OPTIONS request, whereas the second is your POST request.
The first request is what's known as a Preflight request and asks the remote server what remote hosts are allowed to connect and what methods they are allowed to call. If this step fails, then you'll see an error in the browser saying the request has been "blocked by CORS policy".
If the preflight request is successful, then the second (POST) request is made.
Depending on how the server is configured, you may need to have it handle OPTIONS requests differently, so that it doesn't perform the same action twice.

Chrome not adding headers in ajax requests from iframe, Firefox ok

I've got a situation where I'm sending ajax requests from iframe, to same domain as original page, this Iframe loaded from same domain. Say, original page address is http://server/client and iframe src is http://server/client/addin1/view.html
From Iframe I make initial xhr request to api: POST http://server/api/connect which returns 201 with token in response header and a cookie.
Now I make next call to different api method, say, GET http://server/api/status, but in this case I add the token header, and I assume the received cookie will be included by browser - it's HttpOnly, my xhr has withCredentials: true.
The magic is: in FF it works ok, both token and cookie are set and sent, in chrome the token header is not added and cookie is not sent. I've verified that in both cases xhr.setRequestHeader(...) gets called, and just to be 100% sure I've verified with wireshark what gets actually sent.
Any idea why chrome, behaves differently from FF? Maybe I'm missing sth simple.
thanks,
Ɓukasz
I had a similar problem to yours and I was able to fix my CORS issue following this MDN article CORS (MDN), see the section on Requests with credentials. There you'll find that you have to set the xhr options withCredentials. Here's the example they use:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler; // Needs to be implemented
invocation.send();
}
}
Hope that helps!

Javascript post requests cross domain with cookies

Using Javascript I want to make multiple POST requests cross domain. In the first instance, I store the response cookies in a variable, then I resend for a second POST request..
For example, in ruby i'd do something like this:
#http = Net::HTTP.new("myhost.com", 80)
// first request
data = "param1=xxxx&param2=yyyy&param3=zzzz"
resp = #http.post("/firstrequestform", data, {'User-Agent'=>'me'})
// second request
#cookie = resp['set-cookie']
headers = { "Cookie" => #cookie, "Referer" => "http://myhost.com/firstrequestform" }
data = "param1=xxxx&param2=yyyy&param3=zzzz"
resp = #http.post("/secondrequestform", data, headers)
Is it possible to do this in Javascript given cross domain restrictions. Maybe possible using an iframe, but how would you control the cookies? I'd also like to set custom headers within the iFrame, such as the Referer header.
If it's not possible, does anyone know of a browser plugin that can be used to do this?
Thanks.
UPDATE
Unfortunately in this case its not possible to route any request through a 3rd party server (all the code has to be on the client side).
Simplest would be use your server as a proxy. Make an AJAX request to your server, and use your Ruby code shown to make request to other domain and output the response to AJAX request

My AJAX request object doesn't properly resolve the protocol portion of the URL

I'm trying to send an AJAX request from a secure page, but the XMLHttpRequest object doesn't properly resolve the protocol portion of the URL. This behavior is identical in Safari, Chrome, and Canary.
Here's my JavaScript:
function sendGETRequest(url, params, callback) {
"use strict";
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status !== 200) {
callback({ajaxError: true, status: req.status});
} else {
callback(req);
}
}
};
req.open("GET", url + "?" + params, true);
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send();
}
Here are some different URLs passed to sendGETRequest(), along with their results:
url = "ajax/";
GET https://mydomain/mypage/ajax/?params 404 (NOT FOUND)
The above is the expected behavior: the relative url is correctly resolved with protocol intact.
url = "/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the realtive url is correctly appended to the domain root, but with the wrong protocol.
url = "https://mydomain/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the protocol is just ignored.
To be clear, I'm not trying to work around the same origin policy; I want to send an AJAX request from a secure page to a resource with the same (secure) origin. How can I accomplish this simple task?
There is a conversation here about this topic: http://bytes.com/topic/javascript/answers/459071-ajax-https
One of the last posts states "Just to be absolutely unambiguous; XML HTTP requests work over https
exactly as they do over http. If they did not our QA department would
have said something by now as they test over https almost exclusively"
Perhaps the server is not using Https (ssl) at the point where the request is being made: mydomain/ajax/.
This has nothing to do with HTTP and HTTPS. As you mentioned in a comment, the request is never being sent due to same-origin policy. How can the request be using the wrong policy if the request is never sent? What is confusing you is that whatever program/add-on/tool/etc that is generating the error message is showing "HTTP" instead of "HTTPS". The request IS and ALWAYS respects HTTPS when HTTPS is set.
Your real issue is quite simply that you are violating cross-origin policy. See this:
https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
You cannot go UP the directory tree, only down. In the first example, you are requesting a subfolder. That's fine. In the second and third examples, you are requesting a page from a parent directory (ie, instead of https://mydomain/mypage/ajax/ you are asking for https://mydomain/ajax/. You cannot make a request up a directory tree like that.
Either move your index page up to the root of the domain, or change the same-origin policy header being sent on the files, or make a sub directory on the server handle the request (you can use something like PHP's include to just include the parent file).
This is a bug in WebKit. It's been fixed in Safari 5 for Lion but not Snow Leopard, and it's been fixed in Chrome but not Canary,... helluva a bug.

What is 'xmlhttp.setRequestHeader();' and in which situations is it used?

I stumbled on this command while learning AJAX. The guy who made the tutorial didn't explain this command, what do the parameters inside the command mean and what is it used for... Below is the code I used it in:
<script type="text/javascript">
function insert(){
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
};
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById('message').innerHTML = xmlhttp.responseText;
};
};
parameters = 'insert_text='+document.getElementById('insert_text').value;
xmlhttp.open('POST','ajax_posting_data.php',true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send(parameters);
};
</script>
HTTP is a protocol. Part of that protocol is the concept of request headers. When an xhr happens, text is exchanged between the client and server. Request headers are part of the text that the client sends to the server.
This is a way to set the request headers. The arguments you see are
1) the header to set (in this case, Content-type)
2) the header value. (in this case, x-www-form-urlencoded)
See this for more info.
HTTP requests are messages passed from one computer system to another according to a set routine (a 'protocol' - here HyperText Transfer Protocol) in order to do things like send data, ask for data to be sent back, update data previously sent, etc.
A header is basically a piece of information about the data in the body of the HTTP request. Its purpose is to tell the machine receiving the request what type of data is enclosed in the body of the request, its formatting, the language used, if it's to set a cookie, the date, the host machine, etc.
More than one header can be put on a HTTP request and each header has a 'name' and a 'value' component. On web pages they look like
<meta name="........" content="............."/>
and you find them just below the top of the web page within the element.
To enable people to send HTTP requests from within a JavaScript function, we create a new XMLHttpRequest object, just as your code does so with
const xmlhttp = new XMLHttpRequest();
To this new empty object you intend to add data. Despite its name, XMLHttpRequest also allows sending data in a number of formats other than XML, e.g. HTML code, text, JSON, etc. In your example each data name will be separated from its value by an "=" character and each data/value pairing will be separated from the next pairing by an "&" character. This kind of formatting is known as URL encoding.
We have to tell the receiving computer how the data within the HTTP request body is encoded. There is a standard header to convey this and it is added to the request via the method setRequestHeader(..). This method uses 2 parameters, the header name and the header's value. All this operation is achieved in the line
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
This setRequestHeader(..) method must be applied to the request after the request is characterized with the open(...) method but before the final request is sent off with the send(.) method.
The open(...) method defines: (1) the type of HTTP request, e.g. GET/POST/PUT etc; (2) the web page that contains the handling script for this request, e.g. some .php file or Node.js request endpoint that makes the appropriate query to the back end database; and (3) the nature of the request dynamics, e.g. asynchronous requests are assigned a value 'true', synchronous requests are assigned 'false'.
The send(.) method attaches the data to be sent within the body of the request, in your case the variable called 'parameters'.
On your broader question of which situations setRequestHeader(..) is used, I would say that it is used in most HTTP request situations. But some types of data added to the body of a HTTP request invoke a default setting for the 'Content-Type' header.
It is exactly what it says. It will set a "header" information for the next XMLHttpRequest.
A header is pretty much a key/value pair. It is used to transmit "meta" information to the target server for the ongoing request. In your particular instance, its used to tell the server which content type is used for this request.
It sets the Content-type HTTP header to contain url encoded data sent from a form.

Categories

Resources