I have an application that creates Cloud Front cookies using the AWS CloudFront API and Lambda. Unfortunately I can't set cookies using the standard HTTP response format and have to use document.cookie to set cookies to my users' browsers from an HTML page. The cookie includes a policy to grant access to content, a signature to confirm authenticity of the cookie, and key-pair ID. A back-end script on Lambda creates the cookie and sends it to the requester as a payload, which then gets passed as a variable to document.cookie.
I've read a lot about securing cookies (HttpOnly, session cookie, secure flag, etc.) and I'm trying to understand the security risks of document.cookie. Is there a difference between setting cookies through Http response and document.cookie in the context of security? Would it be possible for a malicious user to insert their own policy into the cookie as the cookie is created client-side, giving them access to other content despite the page being read only?
Here's some code for reference:
payload = data["Payload"]
jsoned = JSON.parse(payload)
cookie = jsoned['cookie']
redirectUrl = jsoned['redirectUrl']
document.cookie = 'CloudFront-Policy' + "=" + cookie['CloudFront-Policy'] + "; path=/mydirectory";
document.cookie = 'CloudFront-Key-Pair-Id' + "=" + cookie['CloudFront-Key-Pair-Id'] + "; path=/mydirectory"
document.cookie = 'CloudFront-Signature' + "=" + cookie['CloudFront-Signature'] + "; path=/mydirectory"
My first time posting to this. Thanks for the help in advance.
-Ken
Is there a difference between setting cookies through Http response and document.cookie in the context of security?
Not really. An HTTP cookie can be set with httponly, but that's a only very weak mitigation against XSS, not really a proper security measure in itself.
Would it be possible for a malicious user to insert their own policy into the cookie as the cookie is created client-side
Yes, but it already was for the HTTP cookie; they're both stored client-side and thus within reach of an untrusted client.
This is what the signature is for, right? If it's correctly implemented it should prevent tampering with the content it signs.
Nothing of "direct" value should ever be stored in a cookie, period.
All validation / processing of the cookie's value should occur server-side (regarding any sensitive information) and the only thing a cookie should contain is some sort of guid (or perhaps a couple of guid's.) And all "client-side" id's that are stored in a cookie, should be encoded in a manner to both prevent tampering & detect tampering on the server side.
In reference to the comments, I stand by this statement ...
"Any information given to the client, should be considered compromised."
... and will expand my answer ... You have no idea what "client application" will be used as it doesn't have to be a "browser" (Postman / custom apps can interact with your website directly, with the intention of directly examining everything you send) as well as proxies (or worse malicious man-in-the-middle apps), network sniffers, etc ... so that being said, both the "client side application / 'loaded page'" && any other data (including cookies) should be considered compromised from the perspective that you should 'not' consider any aspect guaranteed with respect to a future client response.
i.e. Here is an example of a vulnerability...
you have a site that uses the value in a cookie to restrict (using client-side javascript) the options in a drop-down list (or some other functionality)
this would be a bad practice, as the user can attack this many different ways...
"modify" the cookie values
"edit" the client side javascript in many ways
"manually" submit any "response" to your web application endpoints
essentially spoof any value to any input
So in summary, anything given to the client should be considered "insecure", and you need to handle any "return values" from the client as "compromised / malicious".
Related
Not sure if the title summarises my question well.
Basically, I am trying to authenticate routes such as checking if user exists etc. I only want to allow
requests coming from my frontend application to be approved, but, since no user is signed in there is no token to send.
Api request -
mywebiste/checkUser/email
This route is unprotected on my backend because no user is logged in.
BUT I want to protect this route, in such a way that it's accessible only from the frontend.
Some ideas I came up with were adding specific headers tag from the frontend and check them on the backend, but that could be easily replicated, is there something more secure like using tokens etc.
I am using React and Node.js
Same origin policy is going to give you some basic protection, but basically if an API endpoint is exposed publicly, it's exposed publicly. If you don't want that route to be publicly accessible you need to add access control.
If you use that route to check if a user is already registered, you could, for example, merge it with the user registration route and send a different error code if the user already exists (which is not a great idea because it leaks which emails are registered on your system).
You can verify that a request was originated by a user (by authenticating him) but you cannot verify that a request comes from a particular client because of these two reasons :
If you include some API key in your client (web page or other), it's easily retrievable by everyone (the best thing you could do is offuscate it which makes things slightly harder but still possible)
If you send an API key over the network it's easily retrievable as well
The only thing you could do is prevent other web pages from calling your backend on behalf of the user, by using CORS (which is actually active by default if you dont specify an Access-Control-Allow-Origin header)
I ended up creating a kind of working solution, so basically, I create a new base64 string on my frontend and attach that to the header while making a request to the backend. The base64 string is different every minute, so even if the header is copied, it differs every minute and is combined with your secret key.
I have made a package so that people can use it if they want - https://github.com/dhiraj1site/ncrypter
You can use it like so
var ncrypter = require('ncrypter');
//use encode on your frontend with number of seconds and secret key
var encodedString = ncrypter.encrypt(2, 'mysecret1')
//use decode on your backend with same seconds and secret
var decodedString = ncrypter.decrypt(encodedString, 2, 'mysecret1');
console.log('permission granted -->', decodedString);
I'm making a chrome extension that injects an iframe on a webpage and show some stuff.
Content loaded in iframe is from https://example.com and i have full control over it. I'm trying to access cookies of https://example.com from the iframe (which i think should be available) by document.cookie. This is not letting me access httponly flagged cookie and i do not know reason for this. After all this is no cross-domain. Is it?
Here is the code i'm using to get cookie
jQuery("#performAction").click(function(e) {
e.preventDefault();
console.log(document.domain); // https://example.com
var cookies = document.cookie;
console.log('cookies', cookies);
var httpFlaggedCookie1 = getCookie("login_sess");
var httpFlaggedCookie2 = getCookie("login_pass");
console.log('httpFlaggedCookie1 ', httpFlaggedCookie1 ); // shows blank
console.log('httpFlaggedCookie2 ', httpFlaggedCookie2 ); // shows blank
if(httpFlaggedCookie2 != "" && httpFlaggedCookie2 != ""){
doSomething();
} else{
somethingElse();
}
});
Any suggestions what can be done for this?
By default in Chrome, HttpOnly cookies are prevented to be read and written in JavaScript.
However, since you're writing a chrome extensions, you could use chrome.cookies.get and chrome.cookies.set to read/write, with cookies permissions declared in manifest.json. And be aware chrome.cookies can be only accessed in background page, so maybe you would need to do something with Message Passing
Alright folks. I struggled mightily to make httponly cookies show up in iframes after third party cookies have been deprecated. Eventually I was able to solve the issue:
Here is what I came up with:
Install a service worker whose script is rendered by your application server (eg in PHP). In there, you can output the cookies, in a closure, so no other scripts or even injected functions can read them. Attempts to load this same URL from other user-agents will NOT get the cookies, so it’s secure.
Yes the service workers are unloaded periodically, but every time it’s loaded again, it’ll have the latest cookies due to #1.
In your server-side code response rendering, for every time you add a Set-Cookie header, also add a Set-Cookie-JS header with the same content. Make the Service Worker intercept this response, read that cookie, and update the private object in the closure.
In the “fetch” event, add a special request header such as Cookie-JS, and pass what would have been passed in the cookie. Add this to the request headers before sending the request to the server. In this way, you can send all “httponly” cookies back to the server, without the Javascript being able to see them, even if actual cookies are blocked!
On your server, process the Cookie-JS header and merge that into your usual Cookies mechanism, then proceed to run the rest of your code as usual.
Although this seems secure to me — I’d appreciate if anyone reported a security flaw!! — there is a better mechanism than cookies.
Consider using non-extractable private keys such as ECDSA to sign hashes of payloads, also using a service worker. (In super-large payloads like videos, you may want your hash to sample only a part of the payload.) Let the client generate the key pair when a new session is established, and send the public key along with every request. On the server, store the public key in a session. You should also have a database table with the (publicKey, cookieName) as the primary key. You can then look up all the cookies for the user based on their public key — which is secure because the key is non-extractable.
This scheme is actually more secure than cookies, because cookies are bearer tokens and are sometimes subject to session fixation attacks, or man-in-the-middle attacks (even with https). Request payloads can be forged on the server and the end-user cannot prove they didn’t make that request. But with this second approach, the user’s service worker is signing everything on the client side.
A final note of caution: the way the Web works, you still have to trust the server that hosts the domain of the site you’re on. It could just as easily ship JS code to you one day to sign anything with the private key you generated. But it cannot steal the private key itself, so it can only sign things when you’ve loaded the page. So, technically, if your browser is set to cache a top-level page for “100 years”, and that page contains subresource integrity on each resource it loads, then you can be sure the code won’t change on you. I wish browsers would show some sort of green padlock under these conditions. Even better would be if auditors of websites could specify a hash of such a top-level page, and the browser’s green padlock would link to security reviews published under that hash (on, say, IPFS, or at a Web URL that also has a hash). In short — this way websites could finally ship code you could trust would be immutable for each URL (eg version of an app) and others could publish security audits and other evaluations of such code.
Maybe I should make a browser extension to do just that!
This question has been asked to me in a interview. i search on web but can't find a thread that explains it in a way that makes sense to me.
Suppose is i had a web service which return a list of something and available
In public Domain(Any body can use That) For security User need A key to Access that web service.
How can i use That web service securely in Ajax.
Problem is if i use Ajax to access that web service any body can able to see my private key,
I suggest for a encryption but i have to pass that key in decrypt(as i get )in form
Than i suggest for a mediator file(at server side) on which i can call that web service but what if somebody directly access that mediator file (i know same origin policy )
i really want to know what are the possible solution to overcome to these problem and what is best practice to make a secure ajax call on rest
In fact, there is a dedicated security flow in OAuth2 for this particular use case called "Implicit Grant Flow".
You could have a look at these links for more details:
http://www.bubblecode.net/en/2013/03/10/understanding-oauth2/#Implicit_Grant
https://www.rfc-editor.org/rfc/rfc6749#section-4.2
If you don't use OAuth2, you can propose the user to authenticate and get back an access token. You could store it within the local storage of your browser but you need to be very careful with XSS. This question (and its answers) could provide you some hints regarding such issue: What are (if any) the security drawbacks of REST Basic Authentication with Javascript clients?.
Hope it helps you,
Thierry
We are using cookies for this. And like the Session we have stored the secure key on the Web-Server. With the Cookie we can get the secure key. So he just see the "key" of his key. There is no option to hide all information from the client. But you can show him information, he cant use directly.
But at all, there is the fishing problem. If someone fishes your cookies, he has your "key" of your secure key. Many others are doing it simular. E.g. Facebook.
This is not specific for Ajax calls, but since it works for both, normal GETs and AJAX Calls, it would be a solution.
If you do not have 100% control of both client side and server side, you may want to use client-side authenticate solution (e.g. Oauth 1 or 2).
If you do have 100% control of both client side and server side, easy way is to use basic authenticate + SSL.
What our project is :
- I have a restful service. We provide restful service in SSL.
- Only our partner companies can use it through internet.
What we did is:
- They have their username/password in their request (is a Ajax) in their internal application (not public-accessed web page)
- sample as following restful code (you can test by Postman):
// to inject request
#Context
private HttpServletRequest request;
#GET
#Path("/testAuth")
#Produces(MediaType.APPLICATION_JSON)
public Response testAuth() {
// TODO
// this is only a template for doing authentication in the near future
String returnString = "";
//check if authenticated
String authorization = request.getHeader("Authorization");
if (authorization == null || authorization.toUpperCase().startsWith("BASIC ") == false) {
//no authenticated
returnString = "{\"testAuth\", \"need authentication\"}";
return Response.status(401).entity(returnString).build();
} else{
String credentials = authorization.substring("Basic".length()).trim();
byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
String decodedString = new String(decoded);
String[] actualCredentials = decodedString.split(":");
String ID = actualCredentials[0];
String Password = actualCredentials[1];
String Result = userAuthenticate(ID, Password);
returnString = "{\"testAuth\", \"" +
" (" + Result + ") \"}";
return Response.status(200).entity(returnString).build();
}
}
I have a web application that talks to a web-server via REST, this web application could be running on a public computer and enables multiple users to logon and logout in a given time period.
All cookies are HTTP-only, this is simply an additional security measure to cover cases of successful XSS attacks. This means that a REST call must be made to force a logout.
My concern is that when the web-server goes down for any reason (or becomes inaccessible eg a network cable being disconnected somewhere). When the user hits logout, there is actually no way of removing the cookie. Meaning that the user may walk away from the PC, meanwhile another user could come along when the connection is restored or server comes back, and just continue using the previous users account.
What is the typical way of dealing with this use case? (admittedly not particularly common).
If I were tasked with something like this, and downtime was a given, I'd probably do something like adding a second cookie, modifiable through JS (let's call it cookiever), which would contain some value that is used as a part of the HMAC signature on the http cookie, ie (pseudocode):
cookiever ||= random
cookie_signature = hex_hmac_sha256(cookie_data + cookiever, "signing_secret")
httponlycookie = urlsafe_base64(cookie_data) + "|" + cookie_signature
set_cookie("httponly", httponlycookie, httponly=True)
set_cookie("cookievew", cookiever)
Normally, cookiever would be set by the server along with the httponly cookie, and is used to validate the cookie on each request. If the user were to request a logout, then you would use Javascript to write an empty value to cookiever, destroying the signing information in the cookie. Thus, even if the httponly cookie can't be destroyed, the cookiever cookie would, and on the next successful request, the httpcookie would fail to validate its HMAC signature, and your server would discard it and force the user to start a new session.
Lets say I have a php generated javasrcipt file that has the user's name, id number and email adress that is currently logged in. Would a simply document.location.href look up prevent remotes sites from determining the currently logged in user?
Would this be safe?
if(window.document.location.hostname == 'domain.com')
var user = {
name:'me',
id:234243,
email:'email#email.com'
};
else alert('Sorry you may not request this info cross sites.');
Initially it appears safe to me.
EDIT: I had initially thought this was obvious but I am using cookies to determine the currently logged in user. I am just trying to prevent cross domain access to the users info. For example if the if statement was removed malicious site A could embed the javascript file and access the users info. By adding the if statement the user js object should never appear. Cross site ajax isn't supported therefore only through javascript insertion could the malicious site attempt to determine the currently logged in user.
EDIT 2: Would checking my http_refer using php be safe? What if caching is also enabled for the client? For example if the user visits my site A where the user script is downloaded and then later visits site B malicious site would the script be cached, therefore bypassing the need for the server to check the user's http_refer?
You're basically saying "here's the keys to the bank vault, here's the guard's schedule, and here's the staff schedule. But hey, if you're not from the Acme Security Company, pretend I didn't give this to you".
"oh, sure, no problem, lemme just pretend to shred this note and go rent a large truck haul away your vault contents with"
You really just don't want to try something like this. Suppose I'm running an evil site; what do I do?
<script>
RegExp.prototype.test = function() { return true; };
</script>
<script src="http://yoursite.example.com/dynamicjs.php"></script>
<script>
alert("Look at the data I stole: " + user);
</script>
No, what you have there is not "safe" in that it will reveal those details to anyone requesting the HTML page containing that JavaScript. All they have to do is look at the text (including script) returned by the server.
What it comes down to is this: Either you have authenticated the other end to your satisfaction, in which case you don't need the check in the JavaScript, or you haven't, in which case you don't want to output the details to the response at all. There's no purpose whatsoever to that client-side if statement. Try this: http://jsbin.com/aboze5 It'll say you can't request the data; then do a View Source, and note that you can see the data.
Instead, you need to check the origin of the request server-side and not output those details in the script at all if the origin of the request is not authenticated.
Update 1: Below you said:
I was specifically trying to determine if document.location.href could be falsified.
Yes, document.location can be falsified through shadowing the document symbol (although you might be able to detect that if you tried hard enough):
(function() {
var document; // Shadow the symbol
document = {
location: {
href: "http://example.com/foo.html"
}
};
alert("document.location.href = " + document.location.href);
})();
Live copy
Cross-domain checks must happen within the browser's internals, nothing at the level of your JavaScript code can do it securely and robustly.
But that really doesn't matter. Even if it couldn't be falsified, the quoted example code doesn't protect the data. By the time the client-side check is done, the data has already been sent to the client.
Update 2: You've added a note about checking the HTTP_REFERER (sic) header (yes, it really is misspelled). Sadly, no, you can't trust that. HTTP_REFERER can be spoofed, and separately it can be suppressed.
Off-topic: You're probably already doing this, but: When transferring personal details you've promised to keep confidential (I don't know whether you have, but hopefully so), use HTTPS (e.g., SSL). But it's important to remember that while HTTPS ensures that data cannot be read in transit, it does nothing to ensure that the origin of the request is authenticated. E.g., you know the conversation is secure (within reason and current practice), but you don't necessarily know who you're talking to. There's where authentication comes into it.