I have stored my JWT token in dynamodb, from a step function used to generate it.
I have fetched the token using api gateway to my static site hosted in s3.
Does anyone know how to save it in cookie?
I am using the serverless framework to deploy my lambdas, if that is any help.
Thanks
To save this (or anything else, really) in a cookie, you need to either respond to a browser request with Set-Cookie HTTP header, see:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
or to set it with client-side JavaScript, see:
https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie
How you do it exactly depends on:
do you want to set it with HTTP headers or client-side JavaScript?
what framework do you use?
how your application is accessed?
how do you want to use that cookie?
Remember that cookie is client-side state and all you tell us about is how you get the data that you want to be stored in a cookie (which doesn't matter) and not how the client-server interaction is done (which is what matters here).
Related
I just want to make sure I've got the overall idea down and don't create an implementation that violates basic security best practices. Can somebody please check my understanding?
As I understand it, a user can log in to my application and the authentication server REST API can return a JWT that is signed, but NOT encrypted. Inside that token I can have claims inside the payload that my client application can access, such as features the user can use on the application. That way my client side website can change functionality based on the user privileges and roles. The JWT claims in the payload are NOT sensitive. They will be strings representing categories for images or documents, things like that.
When the user wants to get additional content (like a document, image, or video) from other REST API endpoints, they submit the JWT along with the GET request. My API can then verify the signature of the JWT and grant API access if appropriate.
This last part is what I'm most unsure about. My intent is to use another authorization server API endpoint which takes the JWT in a POST request and returns a simple "valid/invalid" response. My thought is that my Content Delivery Network (CDN) can use this API to verify that the JWT in possession is validly signed. I believe (and maybe here is where I'm goofing up) that the authorization server API can be publicly accessible to ease use by my other microservices. This seems fine because I'm just giving a boolean pass/fail on the validity of the token so I don't see any need to hide or obfuscate the API. I question this because I know AWS has backend stuff to validate and authorize for API calls but I like the simplicity of just using REST APIs for everything for my first implementation; to maintain simplicity.
So in summary:
1.) Signed, unencrypted JWT with non-sensitive user roles/privileges.
2.) Unencrypted so client side webpage can selectively render content based on user.
3.) Public authorization API that anybody could technically use so that my CDN (and other microservices) can validate JWTs.
Any major issue with this approach? Have I committed any technical sins?
Thank you so much in advance for your time on this matter.
Okay, I think I've sorted this out myself after finding a great video tutorial on this stuff. Below is the video I watched:
https://www.youtube.com/watch?v=_XbXkVdoG_0
I had some misconceptions and this video sorted them out. It appears that what I described in my question is precisely how JWT should be used.
My SPA uses React as front end and laravel API as backend.
When the user logs in (via axios and api), the api returns an access (Bearer token) as response. I use the react-cookie framework to store the access token as cookie in the Browser. This cookie will be read and used for any future request.
Is this the right way to do?
Isn't cookie data just something in the Browser that can be easily obtained by any attacker? Since it is just a file one the computer somewhere.
What is stopping an attacker from grabbing that cookie, impersonate as that user and start performing actions that requires authentication?
The token has a life span of lets say 1 year. It will only be refreshed every time the user logs in. I understand that if I set the life span shorter it will be more secure. However that will mean the user would have to log in constantly?
-----Update-----
Im not sure if any of the provided solution answered my question. A SPA app is front end based and the request can be from anywhere such as Postman, Mobile app, or any third party device that wish to talk to my backed server. So those device needs a way to store some access token locally to be used for any future request.
The only way I know this could happen is for my server to send some auth token to the requester and have it store it somewhere to be used for next request.
In this case, Im not sure if CSRF token or any other means would help my concern?
Just like facebook, if I clear my cache, I will have to re-login. That means facebook is storing something on my location computer so I can be automatically authenticated next time
I just want to add some disadvantages of storing tokens in cookies that you should also be aware of:
The max size of a cookie is only 4kb so that may be problematic if
you have many claims attached to the token.
Cookies can be vulnerable to cross-site request forgery (CSRF or
XSRF) attacks. Using a web app framework’s CSRF protection makes
cookies a secure option for storing a JWT. CSRF can also be partially
prevented by checking the HTTP Referer and Origin header. You can
also set the SameSite=strict cookie flag to prevent CSRF attacks.
Can be difficult to implement if the application requires
cross-domain access. Cookies have additional properties (Domain/Path)
that can be modified to allow you to specify where the cookie is
allowed to be sent.
------- Update -----
You can also use cookies to store the auth token, even it is better (at least in my opinion than using local storage, or some session middleware like Redis). And there are some different ways to control the lifetime of a cookie if we put aside the httpOnly and the secure flags:
Cookies can be destroyed after the browser is closed (session
cookies).
Implement a server-side check (typically done for you by
the web framework in use), and you could implement expiration or sliding window expiration.
Cookies can be persistent (not destroyed
after the browser is closed) with an expiration.
Your JS should not have access to the cookie. There are flags you can set on cookies that will help protect them and make sure they are only used for the correct purposes.
The HttpOnly flag is set on the cookie then JS will not be able to access it but it will still be sent with any request.
The SameSite flag will ensure that the cookie is only sent back to the site that gave it to you. Which prevents leakage.
The Secure flag will make it only send the cookie over a secured connection to prevent someone from sniffing it out of your web traffic.
Edit
You might want to lookup an authorization workflow but the gist of it is this:
User logs in with username and password
A JSON web token is issued upon login from the backend and sent to the browser
The JWT(JSON web token) can be stored in a cookie in the Web Storage(Session Storage) on the browser
Subsequent requests to the REST API will have the token embedded in the header or query string for authorization. With that form of authorization, your REST API understands who is making the request and what kind of resource to return based on the level of authorization
Please see #tpopov answer as he also made some really good points.
I'm struggling to understand how flask_login or django knows when a user logs in that they retain access?
If I were to use ReactJs or Angular with flask-restful or django/tastypie, what is being added to the header/body of future json requests to ensure that my user stays logged in?
This is done via sessions, which is based on cookies. From the Flask documentation:
In addition to the request object there is also a second object called session which allows you to store information specific to a user from one request to the next. This is implemented on top of cookies for you and signs the cookies cryptographically.
and the Django docs:
Django provides full support for anonymous sessions. The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies contain a session ID – not the data itself (unless you’re using the cookie based backend).
So, the requests to the server automatically include a cookie that indicates some ID that the server then uses to figure out what the session data should be for the given user. In general, when Ajax requests are made from client-side applications to the server, this cookie is included and so ensures that the user is considered to be logged in for those requests.
In some cases, you can also (optionally) manually add a special header to HTTP requests to indicate which user is logged in.
See also Securing RESTapi in flask for some more information.
If you use REST service then you should take a look at oAuth. In other words it uses token which you attach to every request from client to server and the last can determine which user sent this request by this token.
On the other hand, you can use cookie or session to determine a user status. And in this case you don't need to add any headers to your request.
Also I recommend you this package for Django - Django Rest Framework (there you can read more about token and auth via REST) and this extension for Flask.
I have to design an API that will support browser plugins only (latest version of Chrome, Firefox, IE). The API will be served over HTTPS. The API will be using a cookie-based access control scheme.
I am wondering what tactics to employ for CSRF prevention. Specifically, I want my API only to get requests from my own browser plugin itself and not from any other pages/plugins.
Would I be able to:
Assume that in most cases there would be an Origin header?
Would I be able to compare and trust the Origin header to ensure that the requests only come from a white-listed set of Origins?
Would this be compatible across the board (Chrome/Firefox/IE)?
I'm aware of multiple techniques used to prevent CSRF, such as the Synchronizer Token Pattern, but I would like to know in my limited scope above, if simply checking the Origin header would be sufficient?
Thanks in advance!
Set a custom header like X-From-My-Plugin: yes. The server should require its presence. It can be a constant. A web attacker can either:
make the request from the user's browser: this sends the cookie, but they can't send the custom header cross-origin; or
make the request from a different HTTP client: they can send the custom header, but they can't send the cookie because they don't know it
Either way, the attacker's request won't have both the cookie and the custom header.
I have a RESTful API which has annotations like #Consumes(MediaType.JSON) - in that case, would the CSRF attack still be possible on such a service? I've been tinkering with securing my services with CSRFGuard on server side or having a double submit from client side. However when I tried to POST requests using FORM with enctype="text/plain", it didn't work. The technique is explained here This works if I have MediaType.APPLICATION_FORM_URLENCODED in my consumes annotation. The content negotiation is useful when I'm using POST/PUT/DELETE verbs but GET is still accessible which might need looking into.
Any suggestions or inputs would be great, also please let me know if you need more info.
Cheers
JAX-RS is designed to create REST API which is supposed to be stateless.
The Cross Site Request Forgery is NOT a problem with stateless applications.
The way Cross Site Request Forgery works is someone may trick you to click on a link or open a link in your browser which will direct you to a site in which you are logged in, for example some online forum. Since you are already logged in on that forum the attacker can construct a url, say something like this: someforum.com/deletethread?id=23454
That forum program, being badly designed will recognize you based on the session cookie and will confirm that you have the capability to delete the thread and will in fact delete that thread.
All because the program authenticated you based on the session cookie (on even based on "remember me" cookie)
With RESTful API there is no cookie, no state is maintaned between requests, so there is no need to protect against session hijacking.
The way you usually authenticate with RESTFul api is be sending some additional headers. If someone tricks you into clicking on a url that points to restful API the browser is not going to send that extra headers, so there is no risk.
In short - if REST API is designed the way it supposed to be - stateless, then there is no risk of cross site forgery and no need to CSRF protection.
Adding another answer as Dmitri’s answer mixes serverside state and cookies.
An application is not stateless if your server stores user information in the memory over multiple requests. This decreases horizontal scalability as you need to find the "correct" server for every request.
Cookies are just a special kind of HTTP header. They are often used to identify a users session but not every cookie means server side state. The server could also use the information from the cookie without starting a session. On the other hand using other HTTP headers does not necessarily mean that your application is automatically stateless. If you store user data in your server’s memory it’s not.
The difference between cookies and other headers is the way they are handled by the browser. Most important for us is that the browser will resend them on every subsequent request. This is problematic if someone tricks a user to make a request he doesn’t want to make.
Is this a problem for an API which consumes JSON? Yes, in two cases:
The attacker makes the user submit a form with enctype=text/plain: Url encoded content is not a problem because the result can’t be valid JSON. text/plain is a problem if your server interprets the content not as plain text but as JSON. If your resource is annotated with #Consumes(MediaType.JSON) you should not have a problem because it won’t accept text/plain and should return a status 415. (Note that JSON may become a valid enctype one day and this won’t be valid any more).
The attacker makes the user submit an AJAX request: The Same Origin Policy prevents AJAX requests to other domains so you are safe as long as you don’t disable this protection by using CORS-headers like e.g. Access-Control-Allow-Origin: *.