Are there any security issues with getting a cookie with jquery and sending it via nowjs function as opposed to getting it via the request on the server?
var session = $.cookie('session_cookie');
now.distributeMessage(session);
vs
req.headers.cookie
I don't see the reason to send cookies from the browser side, since they are transmitted either way each time you make a request to the server. No need to duplicate this feature, just use:
req.headers.cookie
In an iframe in IE (perhaps an edge case) cookies are not always sent (unless you transmit a security policy --which gets complicated--). It is just easier to use Javascript cookies and pass them by socket.emits (or by the convenient now.calls).
Related
I have a server that stores session cookies and you can log onto it using a page (foo.com/login.html) that runs in the browser. The browser then stores a session cookie for this domain.
Now I want another page (bar.com) upon initialization to make a GET request using JavaScript to the first page (foo.com/authenticate) which should check if a session cookie exists in the browser and validate it, if correct he should respond with the session's username (however this is retrieved from the cookie). Of course I cannot check in bar.com's JavaScript if there exists a session cookie for foo.com.
Trying to solve this I ran into a few problems, one of which is of course CORS. I managed to avoid this problem by placing a reverse proxy in front of foo.com that adds all required CORS headers to the response. besides adding the headers, the proxy only tunnels requests through (eg. rev-proxy.com/authenticate -> foo.com/authenticate)
Now when I call the handler through the rev proxy from just another browser window directly (eg. rev-proxy.com/authenticate), I get the correct response. The handler from foo.com's backend finds the session cookie, reads out the username and passes it back. BUT when I try to make the same call from JavaScript inside bar.com (fetch("rev-proxy.com/authenticate")), I receive null, meaning he did not find the cookie (note that the request itself has status 200, meaning it did reach the backend of foo.com).
I have the feeling I am missing a crucial point in how cookies are used by browsers but I cannot find any useful information on my specific problem since I believe it is a rather unusual one.
See the MDN documentation:
fetch won’t send cookies, unless you set the credentials init option. (Since Aug 25, 2017. The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.)
So I am trying to set up environment for local development to pull data from my dev server at dev.mydomain.com.
The tornado REST server serving data uses a cookie-based authentication.
To obtain the cookie I sent an AJAX post login request to the server (from the website at localhost), and the secure cookie comes back in a response. I can see that in the chrome console (network->cookies). It has the proper name, value, domain (dev.mydomain.com) and everything.
Yet, the cookie doesn't get set and the REST requests that follow fail. It is not cross-origin related. If I go to dev.mydomain.com and log in manually in another tab the cookie gets set correctly and all my subsequent requests sent from local domain work fine (since they grab the now-existent cookie).
All my requests contain this:
xhrFields: {
'withCredentials': true
}
And this is how my tornado server sets the cookie:
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1, domain="dev.mydomain.com"
)
Any idea why the cookie doesn't get set if the login request comes from localhost?
I tried mapping 127.0.0.1 to foo.mydomain.com (for whatever that's worth) but this doesn't help.
Also, I cannot grab the cookie with javascript. Tried xhr.getResponseHeader('Set-Cookie');, yields null.
Somehow it makes sense to me that if you set the cookie for dev.mydomain.com that it does neither work for foo.mydomain.com nor for localhost.
What happens if you do something like this:
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1, domain=".mydomain.com"
)
*.mydomain.com might work then.
EDIT:
Actually, I checked over and over again, and I can't find an example where people used the argument 'domain' for set_secure_cookie() but instead this argument exists for 'set_cookie()', as stated in the docs:
Additional keyword arguments are set on the Cookie.Morsel directly.
See http://docs.python.org/library/cookie.html#morsel-objects for
available attributes.
If you are sure about using secure cookies, you should first get sure to use a cookie secret in your application settings
class Main(web.Application):
def __init__(self):
settings = dict(
cookie_secret = "xxxx",
)
then try to set the secure cookie, without specifying the domain
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1
)
I am going crazy with cookies and ajax call.
My configuration is simple. I run a website on 8282 port, (localhost.com:8282). My website calls some webservices on 8080 port (localhost.com:8080). Of course I add a line in my hosts file to avoid localhost trouble :
127.0.0.1 localhost.com
I try to set a cookie when the webservice is called with ajax. Here is my response header that I can see with Chrome debugger :
Set-Cookie:token=Custom eyJ0aW1lc3RhbXAiOiIxNDI0NzE5Mzc5ODY3IiwgImlkIjoiNTRlNzZkZGU2ZDk3ZGM1MjYxZjQzMzFlIiwgInNpZ25hdHVyZSI6Im5tZnFGeEEvYlc0TFJGNFJNb3dBZXJZOUw0aWw0aEorcFh1YUt5b3VFK0k9In0=;domain=.localhost.com;path=/;
The cookie is never stored by Chrome. However, when I use Rest client extension and I call the same webservice, the cookie is stored by Chrome ! So my cookie is well formed but is not stored with ajax call.
It's likely an issue with CORS (Cross Origin Resource Sharing, i.e the fact that the domain of the client and of the target of the AJAX call are not the same). For cookies to work well in a CORS configuration, you need to set the withCredentials flag to true. How to do so varies depending on you AJAX library (if you're using one).
See here: http://www.html5rocks.com/en/tutorials/cors/
In your close reponse of ajax you can set your cookie
document.cookie = "token=Custom eyJ0aW1lc3RhbXAiOiIxNDI0NzE5Mzc5ODY3IiwgImlkIjoiNTRlNzZkZGU2ZDk3ZGM1MjYxZjQzMzFlIiwgInNpZ25hdHVyZSI6Im5tZnFGeEEvYlc0TFJGNFJNb3dBZXJZOUw0aWw0aEorcFh1YUt5b3VFK0k9In0=;domain=.localhost.com;path=/";
Can an AJAX response set a cookie?
Looking for an accepted practice for setting browser cookies within a JSON and Ajax based web application.
The browser seems to not accept cookies from the server for JSON requests. This leaves me with two options that I can see:
When doing operations that need to involve cookies, do not use JSON requests, but rather evaluate the JSON after the text gets to the client using JSON.parse()
Send the cookie information from the server to the client via JSON, then use the browser to set the cookie instead of through server heads. Does this also mean that the cookie information will have to be read on the client and sent back to the server via JSON because the browser will not send cookie information via AJAX JSON requests as well?
My inclination is to go with option #1, but these both seem pretty crappy options. Am I missing something here?
Thanks!
Cookies are sent only if the Domain property matches the domain you are on.
So for example you set a coockie with the domain '.domain.com'. Any requests made to domain.com or any subdomain will contain the cookie, but only that.
For request to other domains you need the coockie set serverside or if the user interacts with a page that sets a cookie for that domain.
2 simple ways to set the cookie that came to mind are:
Obviously, make a ajax call to a script to set the cookie
Do something like this:
HTML:
<script type="text/javascript" src="http://domain2.com/cookie_login_page.php?username=johnsmith&hash=1614aasdfgh213g"></script>
PHP:
<?php
// ... setCookie stuff
echo 'var cookie_set = true;';
?>
I need to make an AJAX request from a website to a REST web service hosted in another domain.
Although this is works just fine in Internet Explorer, other browsers such as Mozilla and Google Chrome impose far stricter security restrictions, which prohibit cross-site AJAX requests.
The problem is that I have no control over the domain nor the web server where the site is hosted. This means that my REST web service must run somewhere else, and I can't put in place any redirection mechanism.
Here is the JavaScript code that makes the asynchronous call:
var serviceUrl = "http://myservicedomain";
var payload = "<myRequest><content>Some content</content></myRequest>";
var request = new XMLHttpRequest();
request.open("POST", serviceUrl, true); // <-- This fails in Mozilla Firefox amongst other browsers
request.setRequestHeader("Content-type", "text/xml");
request.send(payload);
How can I have this work in other browsers beside Internet Explorer?
maybe JSONP can help.
NB youll have to change your messages to use json instead of xml
Edit
Major sites such as flickr and twitter support jsonp with callbacks etc
The post marked as the answer is erroneous: the iframes document is NOT able to access the parent. The same origin policy works both ways.
The fact is that it is not possible in any way to consume a rest based webservice using xmlhttprequest. The only way to load data from a different domain (without any framework) is to use JSONP. Any other solutions demand a serverside proxy located on your own domain, or a client side proxy located on the remote domain and som sort of cross-site communication (like easyXDM) to communicate between the documents.
The fact that this works in IE is a security issue with IE, not a feature.
Unfortunately cross-site scripting is prohibited, and the accepted work around is to proxy the requests through your own domain: do you really have no ability to add or modify server side code?
Furthermore, the secondary workaround - involving the aquisition of data through script tags - is only going to support GET requests, which you might be able to hack with a SOAP service, but not so much with the POST request to a RESTful service you describe.
I'm really not sure an AJAX solution exists, you might be back to a <form> solution.
The not very clear workaround (but works) is using iframe as container for requests to another sites. The problem is, the parent can not access iframe's content, can only navigate iframe's "src" attribut. But the iframe content can access parent's content.
So, if the iframe's content know, they can call some javascript content in parent page or directly access parent's DOM.
EDIT:
Sample:
function ajaxWorkaroung() {
var frm = gewtElementById("myIFrame")
frm.src = "http://some_other_domain"
}
function ajaxCallback(parameter){
// this function will be called from myIFrame's content
}
Make your service domain accept cross origin resource sharing (CORS).
Typical scenario: Most CORS compliant browsers will first send an OPTIONS header, to which, the server should return information about which headers are accepted. If the headers satisfy the service's requirements for the request provided (Allowed Methods being GET and POST, Allowed-Origin *, etc), the browser will then resend the request with the appropriate method (GET, POST, etc.).
Everything this point forward is the same as when you are using IE, or more simply, if you were posting to the same domain.
Caviots: Some service development SDK's (WCF in particular) will attempt to process the request, in which case you need to preprocess the OPTIONS Method to respond to the request and avoid the method being called twice on the server.
In short, the problem lies server-side.
Edit There is one issue with IE 9 and below with CORS, in that it is not fully implemented. Luckily, you can solve this problem by making your calls from server-side code to the service and have it come back through your server (e.g. mypage.aspx?service=blah&method=blahblah&p0=firstParam=something). From here, your server side code should implement a request/response stream model.
Just use a server side proxy on your origin domain. Here is an example: http://jquery-howto.blogspot.com/2009/04/cross-domain-ajax-querying-with-jquery.html
This can also be done using a webserver setup localy that calls curl with the correct arguments and returns the curl output.
app.rb
require 'sinatra'
require 'curb'
set :views,lambda {"views/"+self.name.to_s.downcase.sub("controller","")}
set :haml, :layout => :'../layout', :format => :html5, :escape_html=>true
disable :raise_errors
get '/data/:brand' do
data_link = "https://externalsite.com/#{params[:brand]}"
c = Curl::Easy.perform(data_link)
c.body_str
end
Sending an ajax request to localhost:4567/data/something will return the result from externalsite.com/something.
Another option would be to setup a CNAME record on your own domain to "Mask" the remote domain hostname.