I am interested in how you would determine using XMLHttpRequest if the user had already authenticated with a server? I can send my request and return data but if I refresh the page and request the data again my logon form is firing even though the session time out has not expired.
Any thoughts?
Thanks
Chris
There are a couple options here. Often times a serve will respond with a login form to any unauthenticated request. Thus, if you're making an AJAX request that fetches JSON, you can just look at the content-type of the response, ala xhr.getResponseHeader('Content-Type'). Authenticated responses should be something like application/json, while unauthenticated responses will be text/html (or something like that.)
But... you can also look at document.cookie to see if the user has a session cookie defined. While this isn't a bullet-proof check (the cookie may be invalid, or the server may have additional checks in place that could still fail the request), it's not an unreasonable check to do.
Related
I am trying to write an RSS feed consumer in JavaScript, but unfortunately most feeds do not seem to explicitly set an access-control-allow-origin header on their responses (Even though it is my understanding that the data is for public consumption / scraping).
My question is: Is there a way to load data like this in javascript (Aside from using a server side proxy or turning the project into a browser plugin) given that:
The requests are simple get requests. (So no OPTIONS request would normally be sent even if the access-control-allow-origin header was present)
Cookies / Authentication is not important as the feeds are public. (So withCredentials would be false if it were an XMLHttpRequest)
e.g. Something like:
fetch('http://rss.slashdot.org/Slashdot/slashdotMain', {
crossOrigin: false,
xhrFields: {
withCredentials: false
}
})).then(function(response){
console.log('Got a response!', response);
});
Update
The second part of my question is: Why is this not allowed?
For example: Suppose I for whatever reason navigate to a domain malicious-website.com. It sends a simple Ajax GET request including withCredentials: false to my-bank.com. my-bank.com processes this request, but then the browser blocks the response.
How does blocking the response to this get request improve security?
It does not matter if I am logged in to my-bank.com in a different tab, as no cookies or authorization header is send as per the withCredentials: false directive. The classic XSRF scenario has already been prevented - this request is exactly as if any other user on the internet [including a malicious one] had loaded this resource.
If there was an authentication token in the URL (Such as JWT) then malicious-website.com already has this and can potentially store it for their own use later - blocking this particular response does not change this.
It does not protect the data on my-bank.com since it does not block the request, just the response - if they have a REST style resource that performs an update in response to that GET then I am going to have a bad time. i.e.: The classic CSRF is not prevented unless my-bank.com requires a non simple request on updates (A POST or request with headers so that an OPTIONS request is sent first)
So again, what good does blocking just the response actually do here?
I guess the answer I was looking for was along the lines of: "If simple withCredentials: false requests were also allowed to subvert the same origin policy then a bad actor could do X".
Any ideas on what that X is?
In our application we validate user name/password. Once validation is done, credentials are encoded using base64 and then needs to be set at request header for subsequent rest calls.
Need to set below in request header.
Authorization:Basic AQNLzR69OFTNJE8X
In the response setting as below from the java code,
javax.ws.rs.core.Response.status(200).entity("").header("Authorization:","Basic AQNLzR69OFTNJE8X").build();
And in the javascript tried setting as below,
sessionStorage.setItem('Authorization:', 'Basic AQNLzR69OFTNJE8X');
But in the subsequent rest service calls in the same session can see the header request is not set with authorization. Request to provide some pointers on setting the Authorization in javascript, so that it is retained for the entire session.
I think you misunderstand how authentication works (or should work).
You are supposed to send the Authorization header only once during the authentication. If the authentication is successful, the server sends you back a session cookie and your session is marked as authenticated (server-side).
You never send back the content of the header, and you don't have to send it each request.
1) The Authorization header is not automatically added. But the cookie will be automatically sent.
2) You should not send the credential and return them: for security purposes, you want to transport them the less you can.
3) You don't want to store the credential in the sessionStorage, I don't know if this is a secure place for a password (i doubt it), but here, the password is only encoded in B64, and it's reversable. So it's as well as cleartext (which is bad for a password).
Hopes this helps!
I am having a bit trouble understanding the following code
run.$inject = ['$http'];
function run($http) {
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
$http.defaults.xsrfCookieName = 'csrftoken';
}
as I always thought that csrf is injected into html forms or ajax calls and not cookie, since csrf is a protection against any adversary trying to use your cookie for authentication.
Can someone give a detail explanation on how angular is handling csrf and how does it get the token from the backend?
I can't answer this better than the angular docs themselves do, so I'll just quote:
Cross Site Request Forgery (XSRF) Protection
XSRF is a technique by which an unauthorized site can gain your user's private data.
Angular provides a mechanism to counter XSRF. When performing XHR
requests, the $http service reads a token from a cookie (by default,
XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only
JavaScript that runs on your domain could read the cookie, your server
can be assured that the XHR came from JavaScript running on your
domain. The header will not be set for cross-domain requests.
To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request. On subsequent XHR requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that
only JavaScript running on your domain could have sent the request.
The token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript from making up its own tokens). We
recommend that the token is a digest of your site's authentication
cookie with a salt for added security.
The name of the headers can be specified using the xsrfHeaderName and
xsrfCookieName properties of either $httpProvider.defaults at
config-time, $http.defaults at run-time, or the per-request config
object.
The $http.defaults.xsrfCookieName is just allowing you to specify what the name of the cookie is, otherwise it's going to look for the default XSRF-TOKEN.
On the server side implementation, I'd recommend using some node.js middleware to handle the setting of the initial cookie instead of rolling your own. Take a look at csurf in particular as it seems to be the most popular. You could also try senchalab's csrf middleware. Either of those ought to be enough to get you started.
I know this has been asked countless times, but none of the answers I found described the actual connection to backend.
I have a one-page JS app that communicates with small backend (Django) API. I use session based authentication. User info is cached on first load. If session expires, I need to change page header and flush user info from cache. However, most of my API resources are public and return always 200. Several other resources are private and return 403 if user isn't logged in, which is great as this gives me excatly the information I need. The problem is, some pages access public resources only. In case session is suddenly deleted on backend and user navigates to url that accesses only public resources, user info isn't flushed and I have an UX problem.
My initial idea was to request private user resource (let's call it /users/self/) on every url change which returns 200 in case user is authenticated and 403 in case they aren't. This however requires 1 extra request before every other request for each url change, which isn't really ideal.
Are there any easier techniques I could use in this case? I don't mind even switching to other type of authentication if that would solve the problem.
What i have done and seen for such scenarios is to use some type of http interceptor that intercept all http requests done by Angular and if it finds a response status of 401, such interceptors raise an event using $rootScope.
See one library here https://github.com/witoldsz/angular-http-auth
To use it, one needs to subscribe to the events raise using some type of root controller, which can redirect the user to login page.
See an example here https://medium.com/opinionated-angularjs/7bbf0346acec
Instead of sending a additional auth request, just check in your backend in every request, if the session didnt expire. If the user is not auth, then return a status code.
In angularjs we used a httpResponse interceptor, who intercepts every response and checks against this status code.
Your backend could add a header to the response if the user is still logged in, regardless if the requested resource is public or not. The client can then check the presence of that header and act accordingly.
On both sides this is done with some kind of filter or interceptor. In angular this would be a $http interceptor.
We at work do what others have already told you: use an HttpInterceptor.
We have every response sent from our backend structured in the same way: an object with two fields: a responseCode and the actual response. We vary the responseCode according to what happened in the backend, being success, security alert, or authentication required for that given action the most common cases.
Then the interceptor reacts in the appropriate way according to each responseCode we have defined. In the case of an authentication required, we redirect to the login page, you could do whatever you need. It's working great for us.
I've just noticed it doesn't matter where I put my Authenticity Token when submitting a request via AJAX. I can either append it to the form as POST data, or put it into the Header.
Is there any difference? Especially regarding security?
Additionally:
I didn't encode the Token in Javascript. Am I exposed to something now?
Thanks in advance.
EDIT:
form.on("sending", function(file, xhr, formData) {
xhr.setRequestHeader('X-CSRF-Token', AUTH_TOKEN);
// formData.append('authenticity_token', AUTH_TOKEN);
});
This is my Javascript adding the token to the Header or (commented out) to the POST data. AUTH_TOKEN is the raw key. I did not encode it in any way.
Part one
There is totally no difference if you pass authenticity token via GET params, POST data or request headers (POST/GET params are virtually the same in Rails).
Let's look at the code (not the best code I've ever seen but...)
def verified_request?
!protect_against_forgery? || request.get? || request.head? ||
form_authenticity_token == params[request_forgery_protection_token] ||
form_authenticity_token == request.headers['X-CSRF-Token']
end
Request if valid if (any of following)
protect_against_forgery? is false
request is GET
request is HEAD
token in params equals one stored in session
token in headers equals one stored in session
I should add that token is generated for every request and stored in session for later inspection (if subsequent request is POST/PUT/PATCH/DELETE)
So as you see both ways of passing authenticity token are valid.
Part two
Is passing raw auth token in AJAX dangerous? No, as much as passing it in a form is totally not dangerous. To explain further I will quote an excellent answer in another SO question
Why this happens: Since the authenticity token is stored in the
session, the client can not know its value. This prevents people from
submitting forms to a rails app without viewing the form within that
app itself. Imagine that you are using service A, you logged into the
service and everything is ok. Now imagine that you went to use service
B, and you saw a picture you like, and pressed on the picture to view
a larger size of it. Now, if some evil code was there at service B, it
might send a request to service A (which you are logged into), and ask
to delete your account, by sending a request to
http://serviceA.com/close_account. This is what is known as CSRF
(Cross Site Request Forgery).
original answer: https://stackoverflow.com/a/1571900/2422778
I still consider this question laziness/lack of patience on your side as all I wrote is very well explained both in Rails Guides and on Stack Overflow. Hope next time you will be more persistent in looking for answers before posting here.
Anyway I am glad I could help.
You can see the difference when you use some tool like https://www.owasp.org/index.php/Category:OWASP_WebScarab_Project or http://www.charlesproxy.com/
That are proxies, which you can turn on locally to fiddle with your HTTP requests and responses.
Very useful for web development.
Good luck.