Sending HTTPOnly cookie in response using Rails API application - ruby-on-rails

Correct me if I'm wrong but cookies are just special Set-Cookie: headers, right? Maybe I'm missing something but that always seemed like the case to me. If I set up a Rails API application and want to support sending HTTPOnly cookies (e.g. headers also assume I've got CORS and everything on the client setup etc) I should be able to do this correct?
Basically, my questions are these:
Does bringing back ActionDispatch::Cookies into my middleware and adding include ::ActionController::Cookies in my application controller totally defeat the purpose of an API application?
If it does, can I just send an HTTPOnly cookie through the headers manually?
And if that is so, is it a much bigger hassle to manage cookie headers manually? Is what I'm gaining from leaving the cookie middleware out out weigh handling them manually, if all I really need to do is send one HTTPOnly refresh token?

So I don't need to add back any middleware or include any classes for cookies. I can use reponse.set_header to send a cookie. However, this only lets you send one Set-Cookie header because it will overwrite the last header you set with Set-Cookie as the key. Instead you have access to response.set_cookie which will let you set multiple cookies with each set_cookie call. It also comes with some options that you can set that you would have to add to the value of the header you were sending manually with set_header.
Here's an example I used that allowed me to send a cookie:
response.set_cookie(
:jwt,
{
value: 'this could be a token or whatever cookie value you wanted.',
expires: 7.days.from_now,
path: '/api/v1/auth',
httponly: true
}
)
Check the documentation for this method for other options because there are others.
EDIT: I was having an issue where the cookie was getting sent in the response but not saved (still). It wasn't showing up in the cookie storage so I changed the path of the cookie getting sent to / and then it showed up. I deleted it and then changed the cookie's path to /my/real/path and it worked and was stored in cookie storage. Go figure.

Related

JSESSIONID missing when /xforms-server POST sent by orbeon client side ajax caller

We are coping with orbeon session management:
We have a custom authentication mechanism that works fine on the server (locally), but we got 403 at every /xforms-server call after login when we are trying to use orbeon remotely.
Our custom authentication happens at tomcat/container level, and the result is a standard JSESSIONID cookie that present in the response of the login request.
The "funny" thing is that this JSESSIONID is present at every "normal" browser request (for resources) except these, so those that are trying to reach the /xforms-server
As if the client side javascript would not set this JSESSIONID cookie for the xhr request.
We already set the cookie forwarding described here
We already set the cookie path descibed here
We already raise the log4j level and orbeon debug but we got only the same info that we have already known, that the sessionId cookie was not forwarded to the server.
Do you have any idea what else we could do?
You are saying that the JSESSIONID cookie is not sent by the browser for Ajax requests. The cookie isn't set by JavaScript. It is set by the server with a Set-Cookie header. For instance, with Orbeon Forms deployed on /démo, if you clear your cookies, the first time you make a request to the server, in the response you will see:
Set-Cookie: JSESSIONID=FAD4923E960D0C0341BC750265222FB6; Path=/demo; Secure; HttpOnly
Note the Path=/demo. This is the server telling the browser "don't send the cookie unless it is a request under /demo. Could you try clearing your cookies, and checking what the header looks like? Does it include the path used for the Ajax request?
It might go without saying, but I'll say it anyway ;), in addition to the path, you need to make sure that Ajax request go to the same server from which the page was loaded, otherwise you have no change that the browser will send the cookie.

Why Rails change Set-Cookie header every request for the same session

I'm using Rails 4 with cookie based session store, found that Rails 4 will give me a different cookie every time I refresh the page, but it can still identify me.
Compare it to another rack app which uses Rack::Session::Cookie, it will only send Set-Cookie for the first request, until some changes to session data were made.
Why are they designed differently? Is there any reason behind?
It's because of the way Rails handles session storage and cookie encryption:
the default session store will try to write the session data to an encrypted cookie on any request that has accessed the session (either to read from it or write to it),
the encrypted value changes even when the plain text value hasn't,
the encryption happens before it reaches the code that's responsible for checking if a cookie value has changed to avoid redundant Set-Cookie headers.
I go into much more detail in answering this question: Why is rails constantly sending back a Set-Cookie header?
Rails cookie_store default use the EncryptedKeyRotatingCookieJar, and generate the encrypt_and_sign value. That value use MessageEncryptor#_encrypt method, which use the Random 【cipher.random_iv】. So, every time the same value will generate a different encrypt_and_sign result.

Store JWT token in cookie

This is my setup:
1 authentication server which gives out JWT token on successfull
authentication.
Multiple API resource servers which gives information (when the user
is authenticated).
Now I want to build my ASP.NET MVC frontend. Is it ok to take the token, which I receive after authentication, and put it in a cookie so I can access it with every secured call I need to make? I use the RestSharp DLL for doing my http calls. If it has a security flaw, then where should I store my token?
I would use this code for the cookie:
System.Web.HttpContext.Current.Response.Cookies.Add(new System.Web.HttpCookie("Token")
{
Value = token.access_token,
HttpOnly = true
});
You’re on the right path! The cookie should always have the HttpOnly flag, setting this flag will prevent the JavaScript environment (in the web browser) from accessing the cookie. This is the best way to prevent XSS attacks in the browser.
You should also use the Secure flag in production, to ensure that the cookie is only sent over HTTPS.
You also need to prevent CSRF attacks. This is typically done by setting a value in another cookie, which must be supplied on every request.
I work at Stormpath and we’ve written a lot of information about front-end security. These two posts may be useful for understanding all the facets:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Are you generating your own JWTs?
If yes, you should consider using a signing algorithm based on asymetric encryption, like "RS256" or "RS512" -- this way you can verify the claims in your client application without sharing the private secret.
Do you really need to pass the JWT into the Cookie?
It might be safer to just put a random id in your Cookie, which references the JWT access token, and do the de-referencing magic on the server which serves your web-app.

Setting a cookie on all subdomains in Rails 4 and Ember

We have a Rails application that is the API component running on api.domain.com and a front-end application in Ember.js running on www.domain.com.
When Ember.js sends a POST request to a route in the API, /events, we want the API to set a cookie to remember a unique user identifier.
Hence this method in the Events controller:
def set_tracking_cookie
cookies[:our_company_distinct] = {
value: create_identifier,
expires: 1.year.from_now,
domain: :all
}
end
As you see, the cookie is set on the entire domain, and is set to expire in a year.
The point is that the next time Ember queries the API, it will be able to read this cookie. However, this is not the case.
Each time the front-end queries the API, the API is unable to find the cookie, nor does it show in the cookies in my developer tools.
The Ember requests set the Access-Control-Allow-Credentials header to true, and I can confirm that the cookie is indeed sent in the response from the API with the correct values for domain, name, path, expiry, etc.
Am I missing something?
Thanks!
For anyone else going through a problem sending/receiving cookies in this way, here are some things I found helpful when I was debugging and ultimately fixed the problem:
When you use the Chrome's (or any other browser's) devtools, examine each request and check it to see if the cookie is being sent from the API on the request where you expect it to be sent, and if all subsequent requests from Ember (or whatever other JS framework for that matter) send this request. In Chrome, go to "Network > [request] > Cookies". Ensure that the front end is sending the cookie properly and that it indeed receives it properly.
We found that this was the best way of adding support for the CORS cookies to Ember was to be done like so: http://discuss.emberjs.com/t/ember-data-and-cors/3690

Turning off authenticity token in Rails 2 for web services?

Instead of just filling out the form in HTML it should also be possible to just send a post request containing the params.. Is it possible to turn off the authenticity token if, for example, the Accept flag is set to 'application/JSON' in the HTTP header?
The request forgery protection works on the basis of checking the content-type of requests and it only checks the requests that can be made by a browser. No browser is able to generate a request with the content-type set to "application/json" for example. That's why the rails forgery protection routine won't check it. So, if you want to make a json request to your application, set the content-type header to "application/json" and it should work.
I know there is a way to turn it off for a controller or an action. Not sure about the content type. Wouldn't it be easier to just add the authenticity token to every json request? There are quite few articles around the web how to do it (for example here and here).
Wouldn't it be easier to just add the authenticity token to every json request?
Yes, but then the client would have to send a request first just to get the token and then another with the actual POST request, which does not make sense IMHO..

Resources