how Postman send requests? ajax, same origin policy - javascript

I have found this very useful Chrome extension called Postman. This is a very useful extension especially when you are into programming RESTful applications.
One thing I am confused on is that how this plugin/extension able to send POST request successfully on different domains?
I tried voting in a poll using Postman like this.
After submitting that, the vote was actually counted in, but when I tried doing that using AJAX and JavaScript, it fails, because of different origin policy of browsers.
How is that even possible?
Here is my code using jQuery. I used that in my computer though, localhost.
init: function() {
$.ajax({
url: 'http://example.com/vote.php',
type:'POST',
dataType: 'html',
data: {
id: '1'
},
success: function(data) {
if ( data == 'voted' ) {
$('.set-result').html( 'you already voted. try again after 24 hours' );
} else {
$('.set-result').html( 'successfully voted' );
}
}
});
},

Chrome packaged apps can have cross domain permissions. When you install Postman it promts you that this app will access any domain.
By placing */* in permissions section of your manifest file, you can do this.
Read more here:
https://developer.chrome.com/extensions/xhr.html

You can add the following header to sent Ajax request in postman.
Content-Type application/json
X-Requested-With XMLHttpRequest
Screenshot

Sounds like the site that hosts the poll (the "vote.php" script) needs to have an "Access-Control-Allow-Origin" header set to allow posting from a list of sites (or all sites).
A value of * for the header will allow posting from any website:
Access-Control-Allow-Origin: *
i.e. You could put the following at the top of vote.php
header('Access-Control-Allow-Origin: *');
Chrome extensions and apps are not subject to the same security limitations placed on normal webpages.
Additional debugging tips:
If you're trying to access remote services from web pages you have open on your local file system in your browser, you might find your browser applies different security rules to them than it does to files served from a web service.
e.g. If you open local files from a locational like C:\MyDocuments\weboot\index.htm (Windows) or \Users\joe\Sites\index.html (Mac) in your browser your AJAX request might not work, even with the header specified in most browsers.
Apple's Safari applies almost no cross domain restrictions to files opened locally but Firefox is much more strict about what it permits, with Chrome somewhere in the middle. Running a web server locally (e.g. on http://localhost/) is a good idea to avoid unexpected behaviour.
Additionally, other libraries that provide functions to handle Ajax requests (such as AngularJS) may require other headers to be set on the server by default. You can usually see the reason for failure in a browser debug console.

2021 Oct
In my investigation, I found out that you need an extra field in the header of your request. So simply add the following key-value into the header:
key: X-Requested-With | value: XMLHttpRequest

Related

Force Tampermonkey HTTP version when using fetch

I have a simple test TamperMonkey (Firefox) script that calls fetch.
The script is simple.
(function() {
'use strict';
GM_registerMenuCommand("Test", postData);
})();
function postData(){
fetch('https://https://httpbin.org/post', {
method: 'POST',
headers: HEADERS,
body: JSON.stringify("{test:data}")
})
}
But running this exact same script on different websites gives different requests.
For instance here, on StackOverflow, and on most sites, it will make one HTTP/2 post. And it works.
(Anecdotally on some sites it will first send an OPTIONS request. It is not an issue but just emphasizing the fact that behavior can be different.)
On others (Twitter for instance), it will instead send an HTTP/1.1 POST. And then the API responds with a 202 and nothing happens (the post data that should be mirrored is not returned)
Is there a way to control which HTTP version TamperMonkey uses when making requests?
===
Following #DraganS's comment, I added the (Connection, upgrade) and (Upgrade, HTTP/2.0) headers.
They do not seem to be taken into account (I don't see 'Upgrade' in the final request, and Connection is set to keep-alive.
Interestingly though this makes the websites that didn't before send the OPTIONS request first.
Not on Twitter though, that is still in HTTP/1.1
===
Edit 2: I was initially testing a specific API, but updating to a full testing script that sends requests to httpbin (that should just mirror the request) has the exact same behavior.
===
Starting to think it's not TamperMonkey related.
I'm not getting the error in Firefox but in Chrome, from the console, just doing a
fetch('https://httpbin.org/post', {
method: 'POST',
body: JSON.stringify('{}')
})
on Twitter returns
Refused to connect to 'https://httpbin.org/post' because it violates the following Content Security Policy directive: "connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api-stream.twitter.com https://ads-api.twitter.com https://aa.twitter.com https://caps.twitter.com https://media.riffsy.com https://pay.twitter.com https://sentry.io https://ton.twitter.com https://twitter.com https://upload.twitter.com https://www.google-analytics.com https://accounts.google.com/gsi/status https://accounts.google.com/gsi/log https://app.link https://api2.branch.io https://bnc.lt wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net".
So the cause would be a Twitter CORS policy ? Is it something that is avoidable ? Or does this mean it's just impossible to have a script making requests outside of these from twitter.com ?
The fact that the HTTP version seen in Firefox is different is probably just a side effect.
The presence or not of a preflight OPTIONS request is normal behavior.
The error is due to to the CSP, not CORS like I initially thought (a lot of my previous errors were CORS related).
Solution: Do not use fetch, but the GM.xmlhttpRequest function. It is able to go around CSP, but you will not see it in the console.

Detect if URL supports HTTP2 using AJAX request in Chrome Extension?

I want the user to be able to enter their website URL into an input box that is part of a Chrome Extension and the Chrome extension will use an AJAX request or something similar to detect and tell the user if the server behind the URL supports sending responses via HTTP2. Is this possible?
Maybe the WebRequest has a way of picking up this information? Or the new Fetch API? Could your request tell the server somehow that only HTTP2 replies are understood? I can't see an obvious way.
I know you can use window.chrome.loadTimes().connectionInfo to get the protocol of the current page but this requires loading the whole page which I don't want to do.
Example URLS:
Delivered over HTTP2: https://cdn.sstatic.net/
Delivered over HTTP 1.1: https://stackoverflow.com/
HTTP/2 responses require a "status" response header - https://http2.github.io/http2-spec/#HttpResponse, so to check whether the response is using HTTP/2, you can use the chrome.webRequest.onHeadersReceived event with "responseHeaders" in extraInfoSpec. For example, with your test cases:
chrome.webRequest.onHeadersReceived.addListener(function(details) {
var isHttp2 = details.responseHeaders.some(function(header) {
return header.name === 'status';
});
console.log('Request to ' + details.url + ', http2 = ' + isHttp2);
}, {
urls: ['https://cdn.sstatic.net/*', 'http://stackoverflow.com/*'],
types: ['xmlhttprequest']
}, ['responseHeaders']);
// Tests:
fetch('http://stackoverflow.com');
fetch('https://cdn.sstatic.net');
EDIT: Apparently you can do this with the iframe and webRequest trick! I found a reference gist (but I haven't tested it myself though):
https://gist.github.com/dergachev/e216b25d9a144914eae2
OLD ANSWER
You probably won't able able to do this without an external API. Here's why
1) Using ajax only requires that the server of the url to be tested sends CORS headers back to the user, otherwise the browser will not accept it.
2) You could create an iframe on the fly and use chrome.loadTimes().connectionInfo in the iframe contentWindow but if the server sends X-Frame-Options: Deny header the browser won't let you load the url in the iframe either.
3) Stripping the X-frame headers via webRequest API as mentioned here
Getting around X-Frame-Options DENY in a Chrome extension?
will likely not work, afaik Chrome extension are not allowed to modify the response body.
Possible solutions
1) The problems above could be solved using a simple proxy that adds the appropriate headers. Here's a reference on how to do it using Nginx
http://balaji-damodaran.com/programming/2015/07/30/nginx-headers.html
2) Just create a custom API that does the request for you server-side and parses the result to check for http2 support. If your extension gets popular it would still be fairly easy to scale it up e.g via caching and horizontal scaling.
Hope this helps!

How can solve Access-Control-Allow-Origin error?

I have setup a small web application on heroku.com in Django which returns JsonResponse you can see it here.
{
name: "shubham",
college: "MAIT",
subject: "java"
}
And I also setup server locally on my computer which accepts that JSON and it appends with HTML element here my javascript file :
$(function (){
$.ajax({
type:'GET',
url:'https://justgiveme.herokuapp.com/',
dataType :"Json",
contentType: "application/json; charset=utf-8",
success: function(data) {
alert("Success !");
},
error : function()
{
alert("failed !");
}
});
});
but when I open localhost it gives me alert("failed !") instead of alert("success !"); .
I have check on Chrome console and I found this error :
Any helpful suggestion is appreciable .
You need to enable Cross-Origin-Resource-Sharing (CORS) on your heroku app. Right now its failing because the request isn't coming from the domain which the first resource was retrieved from. In your case, 127.0.0.1.
Here's a starting point for Django on CORS: http://www.django-rest-framework.org/topics/ajax-csrf-cors/
The error you are seeing is because the browser sends a preflight request to check if a cross origin request is allowed. You can see it being sent when viewing the Network tab in the Chrome Inspector. It will be an OPTIONS request to the url that is specified in the ajax.
In order to resolve this issue, the server needs to let the browser know that cross origin requests are allowed. To do this, Django must respond to the preflight request with the Access-Control-Allow-Origin header specified. The header's value must be either be the website you are requesting from or "*" to allow any website.
//Any website
Access-Control-Allow-Origin: *
//Specific website
Access-Control-Allow-Origin: http://www.example.com
A resource makes a cross-origin HTTP request when it requests a
resource from a different domain than the one which the first resource
itself serves. For example, an HTML page served from
http://domain-a.com makes an src request for
http://domain-b.com/image.jpg. Many pages on the web today load
resources like CSS stylesheets, images and scripts from separate
domains.
For security reasons, browsers restrict cross-origin HTTP requests
initiated from within scripts. For example, XMLHttpRequest follows
the same-origin policy. So, a web application using XMLHttpRequest
could only make HTTP requests to its own domain. To improve web
applications, developers asked browser vendors to allow XMLHttpRequest
to make cross-domain requests
you can read more about CORS here .
Detailed explanation of how to setup CORS in Django ?
This is because of no provision in the REST API to handle Cross-Origin-Resource-Request (CORS). To enable it in the REST API, we need django-cors-headers as recommended in Django REST Framework documentation. The minimal settings required are as follows.
Step 0 - install django-cors-headers .
pip install django-cors-headers
Step 1 - In settings.py, add the following entry in INSTALLED_APPS tuple.
INSTALLED_APPS = (
'......',
'corsheaders',
'......'
)
Step 2 - In settings.py, add the following entries at the top of MIDDLEWARE_CLASSES tuple.
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
)
Step 3 - Add the following flag variable in settings.py
CORS_ORIGIN_ALLOW_ALL = True
you can read more about CORS in django here .
We are done !!

local AJAX-call to remote site works in Safari but not in other browsers

I am maintaining a website that uses Javascript. The script uses jQuery and loads some content from the server at which the site is normally hosted.
Just for convenience while maintaining the site, I run a local copy of the site on my iMac. This works perfectly fine when I use Safari. But Firefox, Opera and Chrome refuse to work. I guess it is because of cross-domain-policy. (I couldn't test this with IE, because IE has to run in a virtual machine on my iMac, so for this reason it is not possible to access any local files)
Is there a setting within Firefox and the other browsers where I can tell the browser that it is ok to ajax-load files that are located on a remote server from a local html-page with a local javascript?
In a nutshell: This my html-page:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>some title</title>
<link rel="stylesheet" type="text/css" href="../css/stylesheet.css">
<script src="../js/jquery-2.1.3.min.js"></script>
<script src="../js/myScript.js"></script>
</head>
<body>
<!-- some content with a div-container to receive the ajax-content -->
</body>
</html>
This is myScript.js:
var errorMsg = function (msg) {
//insert the message into the html-page
};
var JSONerror = function (jqXHR, textStatus, errorThrown ) {
var msg = 'JSON-answer: '+jqXHR.responseText;
msg += '<br>'+'JSON-Errorstatus: '+textStatus;
if ($.type(errorThrown) === 'string') {
msg += '<br>'+'Error: '+errorThrown;
}
errorMsg(msg);
};
var JSONreceive = function (JSONobj, StatusString, jqXHR) {
//insert the data in JSONobj into the html-page
}
var StartAJAX = function () {
$.ajax({
url: 'http://my.domain.tld/cgi-bin/myPerlScript.pl',
data: "lastID=" + lastID
+ '&qkz=' + Math.random(),
dataType: "json",
success: JSONreceive,
error: JSONerror
});
};
There is also an event-listener, that listens for page-scroll and resize and checks some other constraints (like: is there already an ajax-call in progress?). This listener calls StartAJAX.
When it calls StartAJAX on a local copy of my page (file:///User/...) within Safari, I get the Ajax-content perfectly fine inserted into my html-document. within the other browsers i get the error-message inserted into the html-page. It is:
JSON-Answer: undefined
JSON-Errorstatus: error
Error:
Why does it work in Safari but not in Firefox, Chrome and Opera?
How can I make those browsers work?
(I need to test it with all browsers, because all browsers render the same html-domument differently, but I don't want to upload all files to the server after every change just to test it.)
EDIT:
After reading some answers, I want to make something clear, that I obviously did not make clear enough:
I am searching for settings in Webbrowsers
I will NOT change the settings of my remote webserver (Apache)
I will NOT manipulate any files on my remote machine (.htaccess)
I will NOT set up a webserver on my local iMac
I will NOT change the code of the AJAX-calls in my Javascript-files
I will NOT change the code of the Perl-Scripts on my remote Server
I can tell you why:
I am just doing a short maintainance, and i am too lazy to upload every manipulated file to the remote machine after I edited it. The settings of the webserver are fine for actual operation. I don't want to change them (and maybe forget the changes before finishing my work). Same for the scripts: Those parts that some of you want to change work fine as they are now. There is no reason to touch the Ajax-Calls, because there is nothing wrong with them in the productive environment.
All I want is that those stupid browsers Firefox, Opera and Chrome behave like Safari and process the Ajax-calls correctly.
BTW:
Please can anyone explain what is so risky to call data via Ajax from an other domain in Firefox, Opera or Chrome while it seems to be harmless doing the same thing in Safari?
CHROME
There is a plugin for chrome that will force it to ignore the security policy. You can also do this with flags. Note, please do not browse the "real web" with this enabled as it is a security risk for your computer.
FIREFOX
This thread indicates that there is presently no way to do this in firefox.
OPERA
Again, there does not appear to be a built in way to ignore CORS policies.
The alternative would be to have the server (http://my.domain.tld) in your case return the proper headers - specifically Access-Control-Allow-Origin:
To avoid this issues, you should develop your page (in your local computer it's ok) using a webserver (like apache, nginx, ...), so, your url ajax calls starts with the protocol http or https, not "file". "File" is the path of your file but using SO path system, not a web server system.
In the other hand, browsers has "Same Origin Policy". This is a security feature but what are the "problems" in web development using ajax calls? Well, your ajax calls always be done to the same server, for example, if you have your web on domain "http://my-domain.com" then your ajax calls must be to the same domain "http://my-domain.com".
To "bypass" SOP in ajax calls, you have three solutions:
Create a proxy on your "my-domain.com" that use curl (in php for example) to retrieve the data and return it to your ajax call
Use JSON-P
Allow your domain in your webserver (.htaccess for example) setting a proper configuration to CORS: http://enable-cors.org/
BTW
I am going to answer: "Please can anyone explain what is so risky to call data via Ajax from an other domain".
(Copy & paste from mozilla MDN https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)
The same-origin policy restricts how a document or script loaded from
one origin can interact with a resource from another origin.
Same-origin Policy is used as a means to prevent some of the
Cross-site Request Forgery attacks.
Due to the same origin policy you aren't normally able to request resources from a different domain. Try adding crossDomain: true to your AJAX request since you are trying to make a request to a different domain.
$.ajax({
url: 'http://my.domain.tld/cgi-bin/myPerlScript.pl',
crossDomain: true,
data: "lastID=" + lastID
+ '&qkz=' + Math.random(),
dataType: "json",
success: JSONreceive,
error: JSONerror
});
Assuming the web site is domain A, and the perl script is on Domain B, you have two options:
1) Enable CORS on the web server at Domain B. http://enable-cors.org/
2) Create a script (php, perl, ashx, etc) on Domain A that calls the script on Domain B. The script on Domain A will act as a proxy and will be allowed by all web browsers.

Server is returning a 303 unless running an insecure version of Chrome

We are writing a web application using the Play framework hosted on Heroku. We wrote a rest API and are accessing it from Chrome. When we use an insecure version of Chrome we get no errors but when we try and use Chrome with the security settings we are getting a 303 from the server with a blank console in Chrome. The server logs say that the cookie isn't being sent with the request. Our headers are being set as:
{
response().setHeader("access-control-allow-origin", "*");<br>
response().setHeader("access-control-allow-methods", "GET,POST,PUT,DELETE");<br>
response().setHeader("access-control-allow-headers", "AUTHORIZATION"); <br>
}
I think we have some Cross Domain problem but I am not sure how to fix it. Any ideas ?
Figured it out. On the AJAX call from the application we needed to add:
xhrFields: {withCredentials: true}
and we needed to remove:
response().setHeader("access-control-allow-origin", "*");
from the server response and only specifically allow the domains we were allowing (localhost).

Categories

Resources