I am unsure of the finer points of the security with regards Access-Control-Allow-Origin and cookies etc.
I was trying to produce an API that allowed authentication from any website. As such I needed to set:
Access-Control-Allow-Origin
to *
and
Access-Control-Allow-Credentials
to true
This is not allowed due to security constraints.
However what would be the problem with setting the Access-Control-Allow-Origin
response header to the value of the Origin
header of the request? Is that a massive security hole?!
e.g. (node)
// CORS
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Headers', 'origin, content-type, accept');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
if (req.method == 'OPTIONS') {
res.status(200).end();
}
next();
});
What would be the problem with setting the Access-Control-Allow-Origin response header to the value of the Origin header of the request?
That's exactly the same as allowing the origin *
and requires no extra effort from any would be attacker. However, you will be able to solve this in a similar way. If you had a pre-approved list of domains that you wanted to allow access, you could check the domain from within the sent Origin
header, and if it matches an allowed one you could then reflect Origin
inside Access-Control-Allow-Origin
.
The security risk with *
is that it'll allow any site to read content that may contain private user data.
As you are allowing any domain to contact your API with credentials (effectively Access-Control-Allow-Origin: *
and Access-Control-Allow-Credentials: true
) you are also allowing other domains to possibly hijack data.
For example, while you victim is logged into your API an attacker forges an email to your victim to go and view a funny video on the attacker's domain www.evil.com
. While the cat video is playing, the attackers domain makes an AJAX request to your API at www.example.com/Get_User_Profile_Details
and reads the user's details including DOB, home address, phone number and other details. Implied Access-Control-Allow-Origin: *
and Access-Control-Allow-Credentials: true
will allow this data to be retrieved by CORS when it is normally blocked by the Same Origin Policy.
So to guard against this you should only output the Access-Control-Allow-Credentials
header for approved domains.
I was trying to produce an API that allowed authentication from any website.
If you do in fact require access from any website then you will need to be careful. You could store the Origin
of the initial authentication request (i.e. the user entering their username and password) against the session ID. On every request you would need to check the Origin
and see if it matches the Origin
stored against the server side session. If so you output the Access-Control-Allow-Origin: https://www.foo.com
header (assuming www.foo.com
is where the user logged into) and if not you don't output Access-Control-Allow-Origin
at all.
You may also find this post interesting.
I'm no expert in these things ...
I would suggest in principal it's a little than just having "*" as it would take some effort for the caller to put in whatever they'd want.
I would suggest if you really want to tie things down (to approved [API?] users) would be to hold the origin in configuration and check each time?
As I say, I'm no expert.
For the record Greg sits opposite me at work .. I could have chatted to him about my point of view, but I wanted SO points :-)