How to send user token with every JsonP request? - javascript

In my sencha touch 2.1, after successful login a token is sent back from service which has to be stored and used with all future service calls. Since I am dealing with remote web service so all the stores use JsonP proxy to fetch data which is why I want to add the token to all such calls. Since JsonP doesn't support headers I am planning to add this token as url param but I am not sure how to do this for all JsonP calls originating from app.
A similar question for AJAX calls was found
Send user details (session token) within every AJAX requests (Sencha Touch 2)
but since JsonP does not support 'beforerequest' event and headers, I am stuck.
Is there any other event I can listen/intercept to add this url param? is there a way to write base proxy class which has this functionality? Please share some examples if you know how to do this.

Ok, I found a way that worked for me.
I extended JsonP proxy and in buildUrl method I appended cached token, and now I an using this proxy in all my stores. Here is the code:
Ext.define('myshop.proxy.CustomJsonpProxy', {
extend: 'Ext.data.proxy.JsonP',
alias: 'proxy.customjsonpproxy',
buildUrl: function(request) {
var me = this,
url = me.callParent(arguments);
if(!Ext.isEmpty(loggedInUserToken)){
url = Ext.urlAppend(url, "token="+loggedInUserToken);
}
return url;
}
});
Please share if you know of other better ways.

Related

Flask JWT Extended set cookie error

I have created an API that is supposed to answer to both mobile devices and web browsers. For example, /web/toys for web and /API/toys for JSON responses. I am using JW Tokens as a means of authentication.
I am displaying forms in HTML and in the background, I call jQuery Ajax's methods to POST to my APIs. I am keeping the access_tokens in the session cookie. To prevent CSRF attacks, I am using Flask-JWT-Extended.
When I decorate a view with #jwt_required and CSRF is set to True, I get missing JWT in headers and cookies, even when the cookies were being set and transferred. I checked the source code and found that it is important to set X-CSRF-TOKEN in the request header. However, since the endpoint answers to both GET and POST calls, how can I set the headers in the GET call without resorting to loading the complete page using jQuery.? Basically, I want to show the form on the webpage, and when the user clicks submit, the form be transferred using jQuery to the existing API. If there is a better way to handle things, I would love to know it.
Thanks!
Author of Flask-JWT-Extended here. As you have discovered, with this extension we are currently doing CSRF protection for every type of request. However, CSRF protection is only really needed on state changing requests: See: https://security.stackexchange.com/questions/115794/should-i-use-csrf-protection-for-get-requests/115800
The benefit of protecting all requests types is that if you have an endpoint that incorrectly changes state in a GET request (there is no technical reason this couldn't happen), it becomes vulnerable to CSRF attacks. Now if the backend is designed more 'up to spec', this is no longer a problem. It sounds like I need to update Flask-JWT-Extended to allow for ignoring CSRF protection on certain types of requests, just like how Flask-WTF operates. I'll try to get this updated today.
Alternately, if your backend is serving JSON instead of html directly (such as a REST api backend and javascript frontend), you can use Ajax to do GET requests with CSRF tokens. In this use case, we could use an Ajax call along these lines.
get (options) {
let self = this
$.ajax({
method: 'GET',
dataType: 'json',
headers: {
'X-CSRF-TOKEN': Cookies.get('csrf_access_token')
},
url: "some_url",
success (result, statusText) {
// Handle success
},
error (jqXHR, textStatus, errorThrown) {
//handle error
}
})
}
EDIT: I also want to preserve the CSRF error messages if the CSRF token isn't present and you are using both headers and cookies for JWTs. Progress on both of these can be tracked here:
https://github.com/vimalloc/flask-jwt-extended/issues/28
https://github.com/vimalloc/flask-jwt-extended/issues/29

How do I set a default Header for all XMLHTTPRequests

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');
};

Making jQuery.ajax request through a proxy server

I'm writing a Chrome extension. If you make jQuery.ajax request for a regular http page from within a page served via https, then the request is blocked by Chrome. I was wondering if I could fetch the requested page using a secure proxy.
So, is it possible to use a generic proxy server for some jQuery.ajax request? If so, how? Note, changing the proxy setting of the browser is not an option.
[And a year goes on...] If I understood your question correctly, you want to change your AJAX request depending on the webpage you are currently at. jQuery provides a number of AJAX related methods which might help you with this.
My suggestion is to use jQuery.ajaxPrefilter and adapt your query to use the proxy instead of the original host. An example from the documentation:
$.ajaxPrefilter(function( options ) {
if ( options.crossDomain ) {
options.url = "http://example.com/proxy/" + encodeURIComponent( options.url );
options.crossDomain = false;
}
});
To spice it up a little bit, you could also use any of the global AJAX event handlers to monitor your request. For example to see if any of the requests fail:
$( document ).ajaxError(function() {
console.log("Somethin' went wrawng!");
});
Yes, it is.
What we did at work was implement a proxy that does exactly that:
It takes web service calls from the same origin, then,
on the server side, maps them to a web service of another origin,
sends them there,
receives the results and
passes them on back to the caller.
This way you can both comply with the same origin policy and work with other origins. However, you will always need a server-side proxy functionality.
You would need an external library to perform Ajax requests via a HTTP Proxy using JQuery. Out-of-the-box, JQuery does not have this functionality. An example of such is https://www.AjaxProxy.com which can be used with your query as follows;
ajaxProxy.proxy.url = "http://your proxy";
ajaxProxy.proxy.credentials.username = "proxy username";
ajaxProxy.proxy.credentials.password = "proxy password";
$.ajax({
type: "GET",
url: "https://ICANHAZIP.COM",
headers: ajaxProxy.proxyHeaders(),
dataType: "text"
}).done (function (data) {
console.log(data);
});

Backbone Fetch Request is OPTIONS method

I have a Backbone Collection object with the URL http://localhost:8080/api/menu/1/featured.
I am trying to perform a fetch operation to retrieve the collection from the URL and parse it. However, on the server side, the method type that I see for this request is OPTIONS. The server is only suppose to support GET method. I am not sure how Backbone is figuring out what method type to use, and why it changes to OPTIONS method type randomly sometimes. I am using a Node.js server to process the request. This code below is pretty much what I did.
var FeaturedCollection = Backbone.Collection.extend({
model:FeaturedContent,
url:function () { return url_featured; },
parse:function (response) {
console.log(response);
return response;
}
});
var featuredCollection = new FeaturedCollection();
featuredCollection.fetch();
It's been awhile, but I remember coming across this before. There's two things this could be: Backbone by default tried to do RESTful API calls to your backend, this means GET, POST, PUT, and DELETE.
Many backends weren't built with real REST support and only support GET and POST. When Backbone sends a PUT or DELETE command your browser (not Backbone) automatically sends an OPTIONS request first to see if it's allowed to make these kinds of requests. If your server answers improperly this call will fail and probably Backbone won't do anything.
To get around this set Backbone.emulateHTTP = true; Or have your server properly answer OPTIONS calls. See the documentation for more info: http://backbonejs.org/#Sync-emulateHTTP
The other issue is that you're making ajax requests cross-domain / sub-domain and you need to properly enable CORS. This also includes properly answering OPTIONS requests.
I had the exact same problem as OP - using Backbone and NodeJS to save data via a CORS POST request would constantly send an OPTIONS http request header, and not trigger the POST request at all.
Apparently CORS with requests that will "cause side-effects on user data" will make your browser "preflight" the request with the OPTIONS request header to check for approval, before actually sending your intended HTTP request method.
https://developer.mozilla.org/en-US/docs/HTTP_access_control#Overview
This thread was what solved my problem - How to allow CORS?
The poster used some middleware to approve PUT/GET/POST/DELETE requests like so -
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
...
next();
and the next(); would allow the OPTIONS check to continue on to the POST request.
Worked like a dream for me, hope it helps someone else too.
Backbone.js maps CRUD methods to HTTP. Taken from Backbone's source code:
var methodMap = {
'create': 'POST',
'update': 'PUT',
'delete': 'DELETE',
'read': 'GET'
};
Backbone.sync = function(method, model, options) {
var type = methodMap[method];
Probably the problem resides on your node.js backend.
What version of backbone are you using? I had exactly the same issue, but then realised I had been using an old version of backbone (0.3.3) in a tutorial. Upgraded the link to the latest backbone.js (0.9.2) and underscore.js(1.3.3) and it sends as a GET.

How to POST data to an HTTP page from an HTTPS page

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.

Categories

Resources