Preventing CSRF with a cross-domain JavaScript call - javascript

I'd like to protect my site against cross-site request forgery. I'm trying to follow these recommendations, by sending a session-specific token along with all requests that need to be protected.
The catch is that I have some requests that are designed to be called by third-party sites, on a different domain. Most of them use JSONP: they make a request to our server using a <script> tag, and the response is JavaScript code that calls a function on their page.
My question is, how to I pass the token in these requests? It seems like the third-party site would need to know the token. I could provide another request that returns the token as JSON, but then untrusted sites could make the same request, get the token, and use it to forge requests to our server.
Is there a better way to do this?

XSRF tokens are usually cookies on your domain that you generate. You really don't want to introduce a mechanism to allow other sites to set those. Verifying that a message comes from a trusted party is better treated as a signature verification problem.
You can have each partner site generate and keep a private/public signature key pair. Then they can send you their public key.
They can then sign their messages to you.
So their request would look like
<script src="https://.../yourservice?partnerid=foobar&signedquerystring"></script>
and then you can signature check that the signed query string was properly signed using the public key you looked up by the key foobar.
You now know to trust the request if it either has your XSRF token or it is properly signed using the private key of a partner you've established a relationship with.
This won't stop someone who can observe a logged in user viewing the partner site from replaying the request, so the partner site and your script should both be loaded via a secure channel (https), just as you would with multiple-use XSRF tokens.

The solution to this problem that I am using is to embed an IFRAME inside the UI of an external widget I am creating. The only drawback here is the possibility of others using this iframe in a clickjacking attack. You could read about that here: https://security.stackexchange.com/questions/13341/security-issues-using-iframes.

I have the simplest solution to the JSONP CSRF problem, Add the "While(1);" or "for(,,);" or throw "F*** U"; in start of your json response data.
Now Any JSONP request end up in a infinite loop. Because you aren’t using a JSONP request, you have the ability to modify the response by this code
JSON.parse(this.responseText.slice("while(1);".length));

Related

NodeJS CSRF Protection with Express, GraphQL and CORS enabled

I am creating a web service very much like shopify but using only JS. Nodejs express for an API with GraphQl and Cors enabled. VueJS for frontend. My authentication is running with JWT. But I have things like anonymous checkout so i need a CSRF protection. The thing is my API is not a router. My router is in the frontend and im only getting the data I need via Graphql through Axios calls to the API. I took a look at the csurf module and tried it out but currently the way im getting a CSRF token to the frontend is with a /getCSRFToken endpoint on the API which i've read is not a good practice and the other thing is It's enabled to access to everyone because of the CORS enabled.
This is the main source of information I have: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
I don't know how to exactly set up the CSRF protection without having am API route for getting the CSRF token and sending it as a cookie through the response and generally make the whole thing secure with the best practices.
I was also thinking about restricting access to the API only for the domains of the shops that are in the system but don't now if that will be any good either.
Any suggestions are welcome
You can generate the cookie client side (using window.crypto), then have the JS read it and send it in a header, the server simply has to verify that they match. But this is vulnerable to the fact the cookie is not HttpOnly (because your JS needs to read it!). For this reason, this method is not best practice, but it is better than nothing.
It also does not prevent users from issuing requests from curl and such once they figure out that they only need to provide a matching cookie and header, but they still cannot issue requests on behalf of other users unless they have the target users authorisation credentials.
There actually isn't anything wrong with having an API route which generates a token per request, although it does result in doubled request density (you need a new token for each request!). The reason for this is that an attacker cannot read the response from an external site (CORS will prevent this). Then you are not vulnerable to any cookie exploit, since you never store a cookie in the first place.
Edit: I see you hint at having CORS * enabled for this endpoint to be public. If your API really is public then you'll have probably better off using OAuth2/JWT authentication instead, this way CSRF becomes irrelevant, since the authentication does not come from cookies.
Trying to keep a value across multiple requests encounters difficulty with history functionality, so it's recommended to either use a token per request or...
You could also store a cookie from the getCsrfToken() request and keep it valid for some time, but make it HttpOnly, since it was issued by the API, the API will be responsible for making sure that it is receiving a valid CSRF token.
The issue with both of the above is that if you want true anonymity then you can't tie these tokens to a particular user, so one user could avoid the CSRF checks on behalf of another by using their own CSRF token!
If you can come up with some way around that whilst maintaining anonymity then the server can check the validity of the tokens that it is receiving, such that one user cannot use their token on behalf of another.
Your last idea (assuming that you want true anonymity) is probably the best. Provided that the user agent is trustworthy, the referer and Origin headers cannot be tampered with, so if you are happy to lock down your API to only the domains which your JS is running on, then doing a referer/Origin check server side will not be easily worked around by an attacker. This isn't best practice, but is practically effective.
Again, curl requests and such can be issued freely, but they can only be issued on behalf of another user if the attacker has the user's authorisation credentials.
The last thing to note is that CSRF is an alternative attack vector to XSS, but if you have XSS vulnerabilities, then CSRF defences usually become obsolete, so make sure that you defend XSS first, before implementing CSRF defence.

POST Call to Authenticate User to Front end Application

I've been tasked with creating an LDAP authentication on a front-end Javascript application.
I am extremely limited on time and have a very small toolset. The toolset is the front-end javascript application and an available C# application which I can make post and get requests to.
I was thinking I could simply make a call such as https://mybackend.com/authenticate
Where I would post a username and password.
And on the backend this would return whether or not the user was valid in the AD. Which I can then use on the front-end to ensure the user has logged in.
Is this approach extremely unsecure or does it have flaws? I'm thinking that if I am posting to the backend above not much will be exposed.
Any tips would be immensely helpful.
Is this approach extremely unsecure or does it have flaws?
This is not insecure, it's the normal way you would do it. One could add more security by adding a CSRF token, which would be validated on the server for any form submit.
And yes, you should send all the data over HTTPS, this will encrypt the payload.
What you are doing is normal for front-end JavaScript framework like Angular. As long as you use Https, you should be ok.
Only issue is how you will handle the subsequence page requests.
There are two ways to handle it –
Easiest way is to use ASP.Net MVC as login page, and use Cookie Owin Middleware. Since same cookie is sent back to server on API calls, you do not need to do any extra works. You can download my sample code at GitHub - OwinAuthenticationService.
Another way is to use Bearer Token in which you will have to send the same token back to server on every page request.
All method are insecure.
Especially without HTTPS.
But you can put the Authentications in the header of message and use a token generated with a key that only server know.

Security on $https requests

Good Morning,
I'm developing an app in ionic and there are some $http requests(angular) that send data to a server controller(yii 1) to save data on database. I finished my app, but it doesn't have security. I was wondering how to protect it, because right now anyone if look my $http request can know what parameters have to send, and kill my app.
What I should do to protect it? Maybe through tokens? I'm really lost with security methods.
Thank you so much,
Carles.
well When you research web application security you will come across Cross-Site Request Forgery (CSRF). This attack vector is taking advantage of cookies, but in a preventable way.
Most attacks focus on stealing your cookies because nearly every website uses cookies as a form of authentication. The setup is this: when a user logs into your server, you set a cookie in the browser. This cookie contains a unique ID which is a link to the user’s session information in your database. The browser supplies this cookie on future requests, and the server knows who you are.
On the surface this sounds not-so-bad, but here is the catch: the web browser can be tricked into making requests to your server, even if the end-user didn’t perform the action themselves.
Using POST Requests
It is sometimes thought that using proper form-based POST requests will mitigate this attack, but that is not true.
Using HTTP-Only or Secure cookies
While you definitely should use these flags on your session cookie, they don’t implicitly stop the attack: the browser still sends the cookies to your domain when a request is made to your domain. Your server does not know if this is a real user or an attack.
How To Prevent CSRF
You can achieve this by relying on a set of rules that browsers respect, called the Same-Origin Policy. This policy asserts that certain sensitive operations are performed by JavaScript code that is running on our website, not some other website.
Angular packages the CSRF token approach, making it simpler for us to implement. For every request that your Angular application makes of your server, the Angular $http service will do these things automatically:
Look for a cookie named XSRF-TOKEN on the current domain.
If that cookie is found, it reads the value and adds it to the request as the X-XSRF-TOKEN header.
Thus the client-side implementation is handled for you, automatically! But this does leave the server side pieces in your hands. You will need to do the following parts:
During login: create the CSRF token (with a random, un-guessable string), and associate it with the user session. You will need to send it on the login response as the XSRF-TOKEN cookie.
Assert that all incoming requests to your API have the X-XSRF-TOKEN header, and that the value of the header is the token that is associated with the user’s session.
That’s it! With a little bit of backend work, you now have a strategy which protects you from CSRF attacks.
you will find a working example of how to prevent CSRF attack here
and for theory of understanding CSRF attacks please follow this reference

WCF REST Authentication - Determine Web Request

What is the best way to determine if a request being made to my REST service originated from a web client. I know I can look at the user-agent, but my concern is that is very easy to spoof.
The reason I want to know who originated the request is because of the following. It is natively built into web-browser that you can't do cross-domain requests. Therefore I don't need to worry about the authentication, because I know the request originated from my website.
My site is built entirely in HTML and Javascript, any suggestions?
Or is there a good way in Javascript to store a hidden username / password I can use just for my website, without it being displayed to the public?
Thanks,
Adam
Anything put in the javascript can be found by using a debugger, such as Firebug, so even though it isn't visible to the user, it can be found by a user.
But, if the javascript first calls to a REST service to get an encrypted token, then the token, which has a timestamp encrypted within it, could be the password, so you then pass the username and token to call the rest of the REST services.
Your server could then validate that it had created the token and that it is not expired, and that the username matches what was encrypted in the token.
But, this depends on if you have any control over the REST service.
The reason I want to know who originated the request is because of the following. It is natively built into web-browser that you can't do cross-domain requests. Therefore I don't need to worry about the authentication, because I know the request originated from my website.
This is not a good assumption. For the reasons you already gave (easily spoofed User-Agent), anyone could make a request to your application. You can even disable cross origin policy in firefox and chrome from the client side - so even if you could verify the request came from a browser, it's still possible to get around your security measures:
Disable same origin policy in Chrome
There are a couple of standard ways to implement security for this kind of service (as James mentioned, assuming you have control over the REST service).
Use Basic Authentication - If your application is communicating with the WCF service via HTTPS, basic authentication is probably the easiest method. See this question
If both your website and your WCF service are implemented using .NET, and your ASP.NET web application is using Forms Authentication, you could share the Forms Auth cookie and use that for authentication. See this question

how to make a cross domain request that isnt forgeable

I need to get some data from Site B into Site A's server side. In order to make the request to Site B to retrieve the data, there are cookies associated with Site B's domain which need to be present. I assume I therefore need to do this in javascript with JSONP?
My ideas was to use JavaScript to make the request to B and then capture the result and stick it a cookie on As domain such that subsequent requests to A would carry the cookie with the returned data (it doesnt matter that it takes two requests to A to get the information to A's serverside). This would work fine, except its completely hackable.
The data itself isn't secret but I need to prevent request forgery or people on Site A calling the JSONP callback function manually, or setting the A cookie manually with stolen or otherwise faked data. Also, is there any other loophole for hacking? This would also need preventing!
The only way I can think of doing this is:
Site A generates a random token and stores it in the session. It then appends this token to the querystring of the JSONP request to Site B. Site B then responds but encrypts the usual data along with the token using digital signing. Site A then sticks this value in a cookie on A. In the next request to A, As server side can capture the cookie, get the value, decrypt it, check the token and if it matches the value in the session, trust the rest of the data.
Does this sound sensible? Is there an easier way? My goal is to reduce the complexity at As end.
Thanks
The way to avoid it being hackable is to have the sites communicate with each other directly, rather than using client-side JavaScript. Write a small light-weight REST API which allows the data to be transferred behind the scenes, server to server.
When linking to Site A, include an authentication token in the URL which can then be checked using the behind-the-scenes call to Site B. This call can transfer any additional required information. The token should probably be IP-bound, and expire after use. Upon success, you can set up your cookie information in Site A, to avoid the need for further round trips.
You could use easyXDM to communicate between the domains. With it you have two javascript Programs, one on the consumers domain, and one on the providers, which can assert the domain of the consumer. Both these Programs can interact with the user, and the user can authenticate itself to both parties. With the providers Program knowing who the user is, and knowing who the consumer is, the provider can pass whatever data it wants to the consumer.
This is what big companies like Twitter, Disqus and LinkedIn use for their API's.

Categories

Resources