3

I want to send custom cookie in POST request to another domain (my domain) from localhost

I set cookie by document.cookie="test=test"; and i can see its set correctly by console.log(document.cookie) , Now When i use following code cookie is not sent though.

  $.ajax({
        url: 'https://secure.domain.com',
        type: 'POST',
        data: "hi",
        cache: false,
        contentType: false,
        processData: false,
        xhrFields: {
            withCredentials: true
        },
        crossDomain: true
    });

I even disabled chrome security by running following command

 -args --disable-web-security --user-data-dir 

Only following headers are sent

Accept: */*
Content-Type: text/plain;charset=UTF-8
Origin: http://localhost:8888
Referer: http://localhost:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.30 Safari/537.36

Note : This is only for my personal use , so i can disable chrome security or modify anything for my use.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
xatap
  • 39
  • 3
  • How would it know what cookies it should send, if not the cookies for that domain? Is it supossed to seed all cookies it knows about for any domain? – Taplar Nov 07 '18 at 19:56
  • Anything is okie , if I can send cookie header in my ajax request itself , that would be more than awesome , All I have is 2 cookie values , that has to be passed into network header – xatap Nov 07 '18 at 19:58
  • I'm asking how you are expecting your browser to know what to do, given that you are asking it to do something non-standard. And how is javascript supossed to be able to change how the browser behaves in that aspect? That's pretty far out of the realm of javascript's control. – Taplar Nov 07 '18 at 19:59
  • Possible duplicate of [How to set a cookie for another domain](https://stackoverflow.com/questions/6761415/how-to-set-a-cookie-for-another-domain) – Ryan Cogswell Nov 07 '18 at 20:00
  • Yes it is not standard , that is why i disabled chrome security and it is for my personal use for some repeated bot task. – xatap Nov 07 '18 at 20:00
  • @RyanC : I dont wanna set cookie for another domain , I just want to set cookie in POST request to another domain – xatap Nov 07 '18 at 20:01
  • That's the same thing. When your browser attaches the cookies to the request, it attaches the ones associated for the domain. The same rule applies for normal requests and ajax requests. – Taplar Nov 07 '18 at 20:01
  • An ajax request to "secure.domain.com" will only send the cookies for that domain. When you set `document.cookie=...` you are setting the cookie for your localhost domain. You can send the information to "secure.domain.com" in a different, custom header that "secure.domain.com" knows to look at, but you cannot send a cookie for a different domain. – Ryan Cogswell Nov 07 '18 at 20:04
  • That is why withCredentials: true is introduced , it works fine in firefox for others – xatap Nov 07 '18 at 20:09
  • `withCredentials` was added to tell the browser it is ok to attach cookies to the ajax request. It has nothing to do with allowing cookies for secondary domains to be included on the request. withCredentials true will allow domain A to send cookies on an ajax request to domain B, but **only** cookies for domain B will be put on the request. – Taplar Nov 07 '18 at 20:15

2 Answers2

2

modify chromium source code is bad idea, for this task you can just create extension to modify request headers, and no need argument -disable-web-security

Create folder with name like headers_ext and add the following files

manifest.json

{
  "manifest_version": 2,
  "name": "Modify Request Headers",
  "version": "1.0",
  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "<all_urls>",
    "tabs",
    "webNavigation"
  ],
  "background": {
    "scripts": ["background.js"]
  }
}

backround.js

function modifyRequestHeaders(request) {
  for (var headers = request.requestHeaders, i = 0; i < headers.length; ++i) {
    if (headers[i].name.toLowerCase() == 'accept') {
      // set Cookie from 'Accept' header value
      headers.push({"name" : "Cookie", "value" : headers[i].value});
      // normalize 'Accept' header value
      headers[i].value = '*/*';
    }
  }
  return {requestHeaders: headers};
}

function modifyResponseHeaders(response) {
  for (var headers = response.responseHeaders, i = 0; i < headers.length; ++i) {
    if (headers[i].name.toLowerCase() == 'access-control-allow-origin') {
      headers.splice(i, 1);
      break;
    }
  }

  // Allow cross domain
  headers.push({"name": "Access-Control-Allow-Origin", "value": "*"});
  return {responseHeaders: headers};
}

var webRequestOptions = {urls: ["<all_urls>"], types: ["xmlhttprequest"]};

chrome.webRequest.onBeforeSendHeaders.addListener(modifyRequestHeaders,
  webRequestOptions, ["blocking", "requestHeaders", 'extraHeaders']);
chrome.webRequest.onHeadersReceived.addListener(modifyResponseHeaders,
  webRequestOptions, ["blocking", "responseHeaders"]);

Now, in Chrome extension page click Load unpacked extension and locate the directory.

the extension above will only modify xmlhttprequest request headers and use Accept header value for Cookie value, It also modify response header to allow cross domain request by adding header Access-Control-Allow-Origin: *.

It seem for Chrome that DPR, Downlink, Save-Data, Viewport-Width, Width headers is not yet in safe-listed so I use Accept header instead to avoid OPTIONS or Preflight request, because many website doesn't support this. And extraHeaders is filter to allow modify or create Cookie.

For more CORS information read here

Make sure you're using latest Chrome and create request like this

$.ajax({
  url: 'https://example.com',
  type: 'POST', // or GET or HEAD
  headers: {
    // it will used for 'Cookie' value by extension
    'Accept': "cookieName=cookieValue" 
  }
});
cieunteung
  • 1,725
  • 13
  • 16
  • Hi , I did Exactly like you told , I get error 500 and CORB blocked error and when i see header in inspect element , cookie header is not passed. – Gracie williams Feb 08 '19 at 17:52
  • Hi , I get error in extenstion , Error in event handler: TypeError: Cannot read property 'length' of undefined on line 16 – Gracie williams Feb 10 '19 at 11:39
  • Hi , how to chat with you ? – Gracie williams Feb 10 '19 at 13:16
  • You had a typo requestHeaders instead responseHeaders , I fixed it , still I get allow origin error – Gracie williams Feb 10 '19 at 13:17
  • Can you please check inspect element ? Cookie is not there in request headers and also I am unable to change origin and referrer too – Gracie williams Feb 10 '19 at 17:13
  • you can't use inspect element or developer tools to see the cookie or other header change, use proxy debugging tools like Fiddler, mitmproxy, wireshark or other to see it. you can change referrer and origin in extension or `modifyRequestHeaders()` function – cieunteung Feb 11 '19 at 06:54
1

This behaviour depends on the client - in case of Chrome, Cookie header is forbidden when used with a XMLHttpRequest and it seems that it cannot be overriden by any command line flag.

Looking at Chromium source code, this is the fragment responsible for it:

// "5. Terminate these steps if |name| is a forbidden header name."
// No script (privileged or not) can set unsafe headers.
if (FetchUtils::IsForbiddenHeaderName(name)) {
  LogConsoleError(GetExecutionContext(),
                  "Refused to set unsafe header \"" + name + "\"");
  return;
}

This method will be called whenever you will call XMLHttpRequest.setRequestHeader(header, value) with Cookie as header parameter and this is what jQuery's $.ajax({}) uses under the hood.

For more information on why this behavior may be disabled by some clients, see this answer.

Here is the complete list of forbidden header names:

ForbiddenHeaderNames::ForbiddenHeaderNames()
    : proxy_header_prefix_("proxy-"), sec_header_prefix_("sec-") {
  fixed_names_ = {
      "accept-charset",
      "accept-encoding",
      "access-control-request-headers",
      "access-control-request-method",
      "connection",
      "content-length",
      "cookie",
      "cookie2",
      "date",
      "dnt",
      "expect",
      "host",
      "keep-alive",
      "origin",
      "referer",
      "te",
      "trailer",
      "transfer-encoding",
      "upgrade",
      "user-agent",
      "via",
  };
}
syntagma
  • 23,346
  • 16
  • 78
  • 134
  • @xatap well, it's open source, so you may easily do it. It seems that removing the call to `FetchUtils::IsForbiddenHeaderName()` I linked to would suffice. – syntagma Nov 07 '18 at 20:32
  • Any tutorial ? I am using mac , I gotta download chromium or I can use Chrome Canary and edit its code ? – xatap Nov 07 '18 at 20:47