This is a research question I've been hitting my head on for a while now. I'm not sure if it's possible but it seems like it should be.
How do I make var token that was defined in them.com's javascript to be visible to us.com's javascript WITHOUT sending information to any of the two servers?
The goal is to save information in the browser to be accessible cross-domain? localStorage, sessionStorage are domain-locked. And set-cookie make it visible to the server... So I cannot use those.
You could give CORS Anywhere a shot.
https://cors-anywhere.herokuapp.com/
CORS Anywhere is a NodeJS proxy which adds CORS headers to the proxied request.
Basically, you can prefix the request URL with https://cors-anywhere.herokuapp.com/.
For example:
fetch('https://cors-anywhere.herokuapp.com/http://your-req-url.com/some-endpoint')
You can also host it yourself. Further reading: https://github.com/Rob--W/cors-anywhere/
Related
We're in the process of moving our frontend into a separate project (out of Django). It's a Javascript single page application.
One of the reasons is to make it easier for our frontend developers to do their work, not having to run the entire project -- including the API -- locally. Instead, we'd like them to be able to communicate with a test API we've set up.
We've managed to solve most of the CORS/CSRF issues along the way. But now we've run into something I can't find a solution for anywhere, despite reading lots of documentation and SO answers.
The frontend and the API are served from different domains (during development localhost and test-api.example.com). Until now, while served from the same domain, the frontend has been able to get the CSRF token from the csrftoken cookie set by the API (Django). But when served from different domains, the frontend (localhost) can't access the cookies of the API (api-test.example.com).
I'm trying to figure out a way to work around this, to somehow deliver the CSRF token to the frontend. The Django docs recommend to set a custom X-CSRFToken header for AJAX requests. Would we compromise the CSRF protection if we similarly served the CSRF token in every response as header and (via Access-Control-Expose-Headers) allowed this header to be read by the frontend?
Given that we've set up CORS properly for the API (i.e. only allowing certain domains to do cross origin requests to the API), JS on 3rd party sites should not be able to read this response header, thus not be able to make compromising AJAX requests behind the back of our users, right? Or did I miss something important here?
Or is there another, better way to achieve what we want?
I didn't understand your question at first, so allow me to summarize: you can't get the CSRF token from the cookie on the client because the Same Origin Policy blocks you from accessing cross-domain cookies (even with CORS). So you're suggesting that the server transmit the cookie to the client in a custom header instead, and are wondering if that's secure.
Now, the documentation does make a suggestion for how to transmit the token if you're not using the cookie: put it in the response body. For example, you could use a custom meta tag. When it comes to security I lean towards using recommended solutions rather than trusting my own analysis of something new.
That caveat aside, I don't see any security problem with what you're suggesting. The Same Origin Policy will prevent a third-party site from reading the headers just as it will the body, and you can opt in to reading them from your client domain with the CORS Access-Control-Expose-Headers header.
You might find this answer interesting, as it lays out the advantages and disadvantages of various CSRF token schemes. It includes the use of a custom response header, and—to the point of your question—confirms: "If a malicious user tries to read the user's CSRF token in any of the above methods then this will be prevented by the Same Origin Policy".
(You might want to look into whether you need Django's CSRF protection at all with your SPA. See this analysis, for example. That's outside the scope of this question, though.)
Assume you already have corsheaders installed. Write a Django middleware and include it in your MIDDLEWARE settings:
from django.utils.deprecation import MiddlewareMixin
class CsrfHeaderMiddleware(MiddlewareMixin):
def process_response(self, request, response):
if "CSRF_COOKIE" in request.META:
# csrfviewmiddleware sets response cookie as request.META['CSRF_COOKIE']
response["X-CSRFTOKEN"] = request.META['CSRF_COOKIE']
return response
expose the header in your settings:
CORS_EXPOSE_HEADERS = ["X-CSRFTOKEN"]
When you make a GET API call from you JS, you should get X-CSRFTOKEN from response header, go ahead and include it in the request header when you make POST PUT PATCH DELETE requests.
I am trying to access this address:
http://52.208.91.209:3000/?paging=1
Accessing manually works fine.
Accessing via an Angular 4 request returns:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
I have googled it for a few hours and did not find a solution.
The only "solution" I have found is using Allow-Control-Allow-Origin plugin.
The address I am trying to access is not mine.
I am just trying to work with it.
I have even read about proxies when using ng serve with angular CLI but didnt fully understand.
All of the solutions I saw are simply a response headers problem on the server side. However, This is NOT my server so I cannot configure it.
Any help would be appreciated. Thank you.
You can change your frontend JavaScript code to instead make the request through a public proxy.
To try that, change your code to use the following URL:
https://cors-anywhere.herokuapp.com/http://52.208.91.209:3000/?paging=1
That’ll cause the request to go to https://cors-anywhere.herokuapp.com, a open CORS proxy that sends the request on to the http://52.208.91.209:3000/?paging=1 URL you want.
That proxy gets the response, takes it and adds the Access-Control-Allow-Origin response header to it, and then finally passes that back to your requesting frontend code as the response.
So in the end because the browser sees a response with the Access-Control-Allow-Origin response header, the browser allows your frontend JavaScript code to access the response.
Or use the code from https://github.com/Rob--W/cors-anywhere/ or such to set up your own proxy.
You need a proxy in this case because http://52.208.91.209:3000/?paging=1 itself doesn’t send the Access-Control-Allow-Origin response header—and in that case your browser will not allow your frontend JavaScript code to access a response from that server cross-origin.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
You can't access that API the way you want to from the browser. There are security measures in place to prevent this from happening. If you do not control the source of the data, you cannot do anything to fix this. Your only option is to have your own server request the data, and you then go through your server to get the data.
Edit: You actually can do this if you only plan to run it locally. Chrome has flags to ignore this security measure. If you don't plan on using this on any machine other than your own, you can force chrome to allow this locally.
The solution I've found was to build my project with the right host using
ng build --production -host=myDomain.com
We have a webservice that is mainly intended to be called from javascript, via jquery's $.ajax(). When we call methods from javascript, we set a security token in a request header. If it's not there, or if it doesn't validate, we return an unauthorized error.
And that's all working fine.
But now we're faced with returning image files. So instead of having javascript call $.ajax(), we're embedding an image tag in the DOM:
<img src='http://mywebservice/imagescontroller/getAnImage?imageid=123'/>
And when we do that, we don't have our security token in the request header. I can think of two "easy" fixes. 1., we simply allow anonymous access to our image URLs, or 2., we pass the security token as a URL parameter.
The first choice is, of course, not a good idea. The second is straightforward enough. But before I settle on this approach, I was wondering if there was some easy way of setting request headers on these sorts of requests, that I was missing.
Ideas?
Easy fix: Use session cookies. That is a cookie without a expiry date. It will automatically transmit with each request and go away as soon as the users closes the browser, or you delete the cookie via javascript.
You simply store your token there and get it delivered for free to your server code.
Have some demo stuff here:
How do I set/unset cookie with jQuery?
If you run the services on another domain, you will need to use CORS to make the AJAX running - otherwise your AJAX will run into the Same Origin Policy. With CORS you can even make the cookies work.
See here: CORS request - why are the cookies not sent?
If you do not want to use CORS, you could also incorporate the service domain into your own via reverse proxying. This will solve the SOP problem as well as make the use of cookies possible. Setting up a reverse proxy within Apache is pretty straight forward.
Is it possible it ONLY JavaScript to hit a specified URL and get a reply as to whether it was possible to hit the URL. I do not need the URL content, and any information of the page, all i need is conformation that the URL was reached and it penetrated all custom firewalls that would site in its way.
No. You would hit the Same Origin Policy wall.
You really need to do it in the server side. In the JS side, you can then test it by a simple ajax to the server side which returns some boolean. Note that this only tests the connection between the server and the desired URL, not between the client and the desired URL. Not sure if that may form a potential problem for your functional requirement.
You can make a HEAD request for the URL. That will just return the HTTP header, but not the content.
If this is Javascript in a browser, this should be easy enough using the XMLHTTPRequest object, provided of course that it's in the same domain so that you have access to request the URL at all.
Only if the requested page have the Access-Control-Allow-Origin header.
This feature add crossdomain origins to your document.
BTW, you only can retrieve it with modern browsers, and need the access to requested page (to set this header).
Look at:
http://www.w3.org/TR/cors/
Just wondering if it's possible to use an XMLHTTPReq to login to a website, and store the cookie. Specifically I'm after the PHPSessionID from the website I am logging into.
I then want to pass this cookie into another request to submit a form.
Any ideas of how to do this?
Cheers,
Nick
You will be able to get your own site's cookies from document.cookie. In the AJAX callback, use a library to parse the value and read the cookie you're looking for.
Of course, if the server sets the cookie HttpOnly (which it should be doing), it won't be available in document.cookie.
At this pont, you need to reevaluate what you're doing:
If the form points to your website, your server script would have access to the cookie anyway.
If you're sending the user's session ID to another domain, why? This is a huge red flag that screams security problem.
If you're logging in to another site, then no – the same-origin policy prevents you from accessing another site's cookies.
Edit: Since this is for your own use, you can do this in a way you're not limited by the browser's origin restrictions. Some thoughts:
You could make a Chrome extension. Extensions aren't subject to origin restrictions, and the development model and API is pretty much the same as what you'd do on a regular web page.
You could use Node, which has no restrictions. You'd be able to invoke your script from the command line, but the API is going to be slightly different that what you'd use in a web page.
Use your language and framework of choice to POST to the login page, get the Set-Cookie header in the response, and use it to send a Cookie header in another POST to the form target.
You can only send cross-origin requests using XHR if both the browser and server support CORS. Additionally, the third party site needs to allow your site to send such requests and to receive its responses. If it doesn’t, you aren’t allowed to send the request or receive its response respectively.