I read this blog What Happens If Your JWT Is Stolen?
The blog says that if one gets the JWT he/she can send requests to the server on behalf of the user.
My question is:- if JWT is stolen and my website don't allow request from unknown domain (due to same origin policy), will I be safe? Is there a way to override same origin policy by the hacker.
I know with XSS attack hacker can send the request from my domain. But here, just assume the hacker only has the JWT and there is no XSS attack.
These policies are a set of rules for browsers. Every HTTP client like curl or Postman can "override" these policies and send custom requests. With Postman you can configure the request as you want.
Same origin policies don't protect your server from attackers. They protect users of your web application from involuntary executing malicious code.
If attackers get a valid token they can send valid requests.
"Can same orgin policy prevent attack if jwt is stolen?" No, they can't.
Your website is a server that answers HTTP(S) requests. An HTTP request is just a bunch of text in a few IP packets. Anybody connected to the Internet can send any text they want to your server. The only information in there which is reliable is the origin and target IP adress of the server and the client connecting (as otherwise the packets won't arrive). Now to ensure that a certain request comes from a certain user, you share a secret with the user, which gets send with the request. When a request arrives, this secret is the only way to authenticate the user. If someone is able to steal or guess that secret, there is no way for the server to distinguish between the user and the attacker.
my website don't allow request from unknown domain
Not quite, the browser which the user uses to store the secret the server gave to the user, ensures that the secret gets only shared with your server. If you disable cross origin sharing, code of other websites the user visits with their webbrowser is unable to perform requests to your server in the background. Thus it prevents that other code uses the secret to perform an action on your server.
In conclusion CORS policies only help to keep secrets secret, if the secret is not secret anymore they won't help.
Related
I currently have my server file set up like so:
export default createServer = (container) => {
const env = process.env.NODE_ENV
const allowedOrigins = process.env.ALLOWED_ORIGINS || ''
const allowedOriginsArray = allowedOrigins.split(",").map(item => item.trim());
const cors = Cors({
origins: allowedOriginsArray,
allowedHeaders: [
'access-control-allow-origin',
'authorization',
'Pragma',
'contact',
],
exposeHeaders: []
})
}
Here, I have origins set to an array of strings from my env file. (I have checked the cors documentation page, I believe there may be a typo, origins should be origin. Either way it does not seem to make a difference).
In my postman request, just to test it out, I have set the origins header to "http://www.test.com" (this is not one of the trusted origins i have in my env file). The requests succeeds when it should fail. I'm wondering if I am testing this incorrectly in postman or if something in my code is incorrect.
The Same Origin Policy is enforced by browsers to stop Mallory's Evil Website from sending your browser some JavaScript that will make an Ajax request to your online banking and send your credit history to Mallory.
CORS is used to relax the Same Origin Policy (so that websites can give access to the data you share with them to certain trusted other websites).
Postman is not a browser. You do not use it to visit websites. It doesn't execute JS embedded in those websites. Mallory can't tell it to make HTTP requests. Only you can do that. Postman doesn't need to enforce the Same Origin Policy, so it doesn't.
You can use Postman to make an HTTP request with an Origin header. Your server can then send back an appropriate Access-Control-Allow-Origin header. However, Postman won't do anything with it except display it in the list of response headers.
It certainly won't relax the Same Origin Policy because it doesn't enforce it in the first place.
From your comment on another answer, I think you have it backwards in your mind; Postman can add Origin because Postman is a tool for "faking" http requests sent by browsers, and to not have the ability to add an Origin would make Postman a poor faker. Origin might be used by some servers and Postman having the ability to send an Origin header means that whatever the server does with it, can be tested.
By and large Origin as a browser-to-server communication is little to do with CORS and SOP, which are a security that works in the direction of "server-to-honest-browser". Inclusion of an Origin header on a request may serve to cause a server to respond with CORS headers but you should not hard-link the two concepts because Origin can be sent for non CORS requests too, and CORS wouldn't specifically require any information in an Origin header in order to work
For CORS enabled scenarios the server says (in a response header) which sites are supposed to be using it and an honest browser (like most people have, when they install latest Chrome) decides whether the page on show should be fetching data from the server or not. Imagine a browser is showing delta.com and a script on the page tries to fetch some data from some back end server. Before it actions the request for the data the script wants the browser makes its own request to the server to check if it's OK; this is an OPTIONS request. If the server responds to the OPTIONS saying "only scripts served from acme.com should use me" and the browser isn't showing acme.com, then the browser doesn't perform the request the script on the page wants to do; instead an error appears in the console, because the delta.com script wanted data and the browser decided not to carry out the request after doing a quick "whisper in the server's ear"
A malicious actor using a browser that doesn't care about CORS requests of "please only use me if you're showing a page from acme.com" will be able to use the server anyway. Postman is an example of such a "browser" - it makes requests at your behest and doesn't care about CORS at all. If you were at all interested in making Postman behave like a browser, you should:
Pretend to be delta.com
Use postman to issue an OPTIONS to server.com (with an Origin)
Postman gets the "i only talk to acme.com" response in the A-C-A-O header
Your own brain decides not to issue the POST request you originally wanted to do, because you've realized you're pretending to be delta.com and the server only talks to acme.com
This would be a more accurate "postman pretends to be like a normal every day browser" iteraction
Origin can feed into CORS; the server could have 1000 different sites it is willing to allow requests from. Clearly sending 1000 site names in every response ("please only use me if you're showing a page from acme1.com, or acme2.com or... acme999.com") would make the response headers huge and the browser then has a thousand sites to check through. If the server is intelligent it can use the Origin to drive the response; if the submitted "Origin: acme547.com" is in the allowed list of 1000 sites the server knows of, then the server can send just that one acme547.com back in the "please only use me if.." header - it doesn't need to send the other 999 sites too. If the Origin is from delta.com, then it doesn't send a "please only use me.." header at all, causing an honest browser to fail the request
The requests succeeds when it should fail.
That's a misunderstanding of how the Same Origin Policy and CORS work. The request shouldn't fail, it's just that the response will or won't include information that a browser can use to determine whether to grant access to the information in it to the origin that requested the information. If the response doesn't allow the origin that requested it, the browser prevents code from the origin seeing the response.
Postman, not being a browser, doesn't do that (not least because there's no origin for it to test the response against).
You can't enforce this at the server side reliably, because malicious actors would just send your server what they think your server wants. The point is for the server to reply with information telling a browser who can access that information.
The goal isn't to keep the information the server sends back private (that's what SSL and authentication are for). It's to prevent a user's stored authentication information or active session from being used to steal information using taht user's credentials. Here's how it works:
Let's say Alice goes online to Bank B to pay a bill, and while she has that session active she also goes to check on what something costs and visits Malicious Site X to find out. Malicious Site X, hoping that Alice just happens to be a customer of Bank B, sends a request to Bank B's website for (say) Alice's account information. Let's say that request is a perfect mimic of a real request, so Bank B's website happily returns the information — because Alice does happen to be signed in with Bank B's site. Oh no!
This is where the SOP comes in. The browser knows that it was code on X's page that requested the information, and knows that it asked for information from Bank B's website. So it checks the response to see if the response specifically says "yes, it's okay to share this with X." Since the response doesn't say that, the browser prevents Malicious Site X from seeing the response and their evil plot to steal Alice's information is foiled.
I am working on an app and would like to use http post requests to send data from client to server, on which the server uses the origin url from the client to allow to use our services, so my question is, can the http url from the client side be faked as a security threat to access my services, and if so, what other alternatives should i take?
An example is, if a client-side script running on a page from foo.com wants to request data from bar.com, in the request it must specify the header Origin: http://foo.com, and bar must respond with Access-Control-Allow-Origin: http://foo.com.
What is there to stop malicious code from the site roh.com from simply spoofing the header Origin: http://foo.com to request pages from bar?
What is there to stop malicious code from the site roh.com from simply
spoofing the header Origin
The browser is. CORS restrictions and headers only work in the browser and the browser is very strict about controlling them. This is specifically to prevent drive-by attacks from random scripts on random sites a user may unknowingly visit. It’s to protect the user of the browser.
However, absolutely nothing prevents a rogue server from sending an arbitrary HTTP request with any arbitrary headers to your server. I could do so from my command line using curl or such right now. These headers do not pose any sort of guarantee or protection for your server.
'on which the server uses the origin url from the client to allow to use our services'
The origin url can be faked very easily.
Add a login with a token to prevent that.
I want to bring a doubt about JWT tokens and CSRF from the Stormpath post that explain the advantages and disadvantages of storing the JWT either in localStorage or cookies.
[...] if you are reading values out of a cookie using JS, that means you
can't set the Httponly flag on the cookie, so now any JS on your site
can read it, thus making it the exact same security-level as storing
something in localStorage.
I'm trying to understand why they recommend adding the xsrfToken to
the JWT. Doesn't storing your JWT in the cookie and then extracting it
out and placing the JWT in the HTTP header and authenticating the
request based on the HTTP header accomplish the same thing as
Angular's X-XSRF-TOKEN? No other domain could make requests on a
user's behalf if you authenticate based on the JWT in the header,
since other domains cannot extract the JWT from the cookie. I don't
understand the purpose of the xsrfToken in the JWT - perhaps its just
an additional layer of defense - meaning that attackers would have to
have a compromised script on your site and CSRF a user at the time. So
they'd have to hit you in both ways to be able to pull of an attack.
The post is linked in this answer where says:
The last thing is to ensure that you have CSRF protection on every
HTTP request to ensure that external domains initiating requests to
your site cannot function.
[...] Then, on every request into your server, ensure that your own
JavaScript code reads the cookie value and sets this in a custom
header, e.g. X-CSRF-Token and verify that value on every request in
the server. External domain clients cannot set custom headers for
requests to your domain unless the external client gets authorization
via an HTTP Options request, so any attempt at a CSRF attack (e.g. in
an IFrame, whatever) will fail for them.
Even if they could set custom headers, they couldn't access the cookie where the JWT token is stored because only JavaScript that runs on the same domain can read the cookie.
The only way they could is via XSS, but having an xsrfToken in the JWT is compromised too if exists XSS vulnerabilities because a malicious script running in the trusted client domain could access the JWT in the cookie and include a header in the request with the xsrfToken.
So the equation should be:
TLS + JWT stored in secure cookie + JWT in request header + No XSS vulnerabilities.
If the client and server are running in different domains, the server should send the JWT and the client should create the cookie with the JWT.
I think that the equation is still valid for this situation.
UPDATE: MvdD agree with me:
As the browser does not automatically add the header to your request,
it is not vulnerable to a CSRF attack
I am the author of the Stormpath Blog Post. Storing XSRF token in the JWT isn't about that it is in the JWT, it is about that it is in a cookie. The cookie should be httpOnly, so you can not read it from Javascript.
Now, I think the point that caused a little confusion is where I talk about angular. Angular sets it's only XSRF cookie as well (which is not httpOnly) to put it into the header at request time (which can only be done by javascript on same domain). These are not the same cookie.
If you think about implementing XSRF support in your application, this has been done with storing server side state and the point of storing the XSRF. Storing it in the httpOnly cookie is about being stateless with XSRF. Here, you would validate the JWT signature, get the XSRF out of the claims, and compare it to the header.
The answer to your question is so that you do not need to store state on your server.
My understanding was this:
Store JWT is an HTTPonly cookie.
In that JWT, store a hashed version of an XSRF token.
Send the client the XSRF token when they sign in so they can store it in local storage
Later when the client sends requests, the JWT is automatically sent with each request via cookies and then you also send the XSRF token via a header or query variable and on the server side, re-hash to compare to what's in the JWT on the server
Your JWT is protected from being stolen in a XSS and you're protected from XSRF. XSS could still execute on your browser but could only do damage for that session in the browser. Ultimately, You couldn't stop someone from writing a really detailed script that just ran on your browser, so conventional safeties to protect from XSS are still needed by the web developer.
What is the challenge/response method to securely authenticate with a Server without HTTPS (without sending out password)?
I have an app (Javascript client) that connects over CORS (authenticate) to our backend which in turns will return a token containing the claim (JWT) over non-HTTPS. The REST is stateless so we do token-based and not have session at all.
When the client gets that token, (containing claim) it is added to the header for each request of the client and therefore the backend knows which User Id is doing that request and do the appropriate thing. So far this works for us. My concern is with the authentication process and with the security of each request.
To authenticate the clients sends out email and hashed password pair, however I want to know if there's a more secure way even without using HTTPS for now. I've read to not send the password but do a challenge/response, but what is the implementation of that idea?
And last question would be, even if we get around with the authentication process securely, how about on each request which contains the token with claim can it be secured also?
There is no possible way to do this securely without HTTPS. For your server to authenticate users, you need some kind of token (cookie, adding to requests like you have, etc.) However, the problem is that, without https, an eavesdropper can add javascript to your page. They can then capture the token and use it themself (stealing all the user's data), or modify it. If you want your product to be in any way secure, you need HTTPS.
Edit: I guess you could store some information about the device sending the request (user agent and such), and only allow the token to be used on that device. However, an attacker could just fake the user agent when they reuse the token, so this wouldn't be too hard to bypass.
Challenge response is a mechanism to send passwords in non-clear way.
1°/ client and server must share a cyphering key : best is to manually add certificate on client but could be a little bit heavy. Another solution is to store the key only one time into localStorage.
2°/ client requests a challenge to server : this is a "phrase" generated by server
3°/ client concats its password with this "passphrase", ciphers and send response to server : Challenge => Response
4°/ server decrypt message, search and remove its passphrase to get password.
I've just learned about CORS, basically because I didn't need it until now.
I've read that CORS enables cross-site origin, by sending HTTP headers with the AJAX call, so the other server can evaluate the request is coming from an approved site.
Now my main concern is, can't the HTTP headers be spoofed? For example, can't an attacker curl a request to the other server, sending the exact HTTP headers that my CORS request does?
In that case, the server will accept the request, and the attacker will retrieve any sensitive data the server will send him.
We all know how easy it is to retrieve javascript from a page, so everything I send with CORS can easilly be seen by keen eyes. HTTP headers included.
So, I guess sensitive information should never be shared within a CORS communication...
Or did I get this everything wrong?
Please shed some light! :)
Thanks
Now my main concern is, can't the HTTP headers be spoofed? For example, can't an attacker curl a request to the other server, sending the exact HTTP headers that my CORS request does?
You have two misconceptions here.
CORS headers are sent by the server not the client (although sometimes a client will make a pre-flight OPTIONS request)
What the Same Origin Policy is defending against
The Same Origin Policy exists to stop Mallory's (evil) website from getting data from Bob's website by asking Alice's browser to request it when Alice visits Mallory's website.
If that was possible, then Mallory could get any information that was supposed to be a shared secret between Alice and Bob (such as Alice's account balance on Bob's banking website).
can't an attacker curl a request to the other server, sending the exact HTTP headers that my CORS request does?
Since Mallory has no way of knowing what security credentials need to be included in the request (because, for instance, they are stored in Alice's cookies for Bob's website): No.
But CORS doesn't matter here, but the Same Origin Policy isn't implemented by cURL since it isn't a browser running JavaScript supplied by arbitrary websites.
I guess sensitive information should never be shared within a CORS communication
It depends on the nature of the information.
If Alice and whatever websites you authorise in the CORS headers are allowed to see it, then it is fine to send it (although you should probably use SSL): So long as you have authenticated Alice's identity.
If only Alice and you site should see it, then don't put CORS headers on it (and don't provide any other way to bypass the Same Origin Policy, such as JSON-P).
If Alice shouldn't see it, then you should never send it to Alice's browser, CORS or no CORS.