This is different than how I've handled sessions in other languages / toolchains (JS + Express, Python + Flask). It looks like you're just putting the whole user object into the actual session cookie. Is putting data into the cookie like this not bad practice? if someone is able to guess a user ID and the shape of the user object would they not be able to fabricate a session token and login? Typically I've seen session management systems create a sessions table that has 3 columns, session_id, user_id, and expires_at. This means you can 1) invalidate sessions you suspect have been highjacked and 2) have unique and hard to guess ID's for current sessions that aren't directly correlated to specific users. This is actually what seems to be in the diagram at the beginning of this video. Then your middleware just gets the session_id from your cookie, ensures it's still valid via expires_at, and then lets you do actions as the user in the user_id column. Maybe I am missing something though? does gorilla sessions handle this sessions table for you in the background?
Very good question, I wish I had addressed this early in the video. Since all of the data is encrypted, a bad actor wouldn't know the shape of the struct/object, it's not encrypted field by field, the whole thing is encrypted. The cookie's encrypted data on the user's machine will appear as gibberish, unless decrypted of course. This is why a bad actor could social engineer someone in the company, get the shape of the struct/object and the user ID, but they still couldn't manufacture a response to impersonate the user. The cookie is signed, which the server checks, so bad actors would need to know that secret set by the server during the creation of the cookie. Also, the server decrypts the data from the cookie, changing it from what looked like gibberish to something more useful. So, the bad actor would need to know the encryption algorithm and the secret used during encryption by the server. This is why social engineering is so scary and why we go to great lengths to protect that secret. In later videos we save that secret in a system variable, so that way the secret isn't in our code which could accidentally get pushed to GitHub or leaked by almost everyone in the company. So, the secret used in production is only saved only the production machine, so we can greatly reduce the number of people who can see it to just those involved in pushing code into production. So, Gorilla sessions does not save sessions in a sessions table on the server, so these cookies, like JSON web tokens, save session data on the client's side. Yes, at first this sounds scary, until we see the inner workings that make it light weight yet secure. The auth function which authenticates our user's session. with the line: session, _ := store.Get(c.Request, "session"), will take the returned http request from the user. This will be decrypted and the signature in the cookie will be checked vs the key configured in the Gorilla sessions cookie store. So, if the cookie wasn't encrypted correctly, has expired or doesn't have the right secret key, then our session struct/object won't be returned into the variable named session. Which we need to have in the line _, ok := session.Values["user"] or else an error will be returned, and they will be sent back to the login page with the: if !ok {...} check. Like I said, very good question, I wish I had explained the points you brought up more clearly. Thank you for bringing this to light as it will help others as well.
@@GrowAdept this is a really solid answer! Thank you for taking the time to respond. I've adopted the gorilla sessions package into a small go web app I'm building with the sessions table approach I described but your description addressed any concerns id have with the approach in this video which is definitely easier to manage! Great video and thanks again for taking the time to address this!
That's great to hear, glad you found it helpful Feel free to share any projects Gin or Gorilla in the comments. It's always good to hear what people are building. I agree your approach will avoid problems with expiring sessions from bad actors in a stateless implementation, which is nice. If you ever feel your app will bump into the 4KB browser cookie storage limit with sessions, you might want to check out JSON web tokens which could get around 5MB. Happy coding and have a great day!
@@GrowAdept If you were an admin and wanted to change a value for the user in the DB like a usergroup for example, and you wanted this to reflect in the users data straight away you would need to update the users session data. How would you go about getting the users session to update it?
I don't have much experience with Power BI but that does sound interesting. Gin makes a lot of the API work easier, and Power BI does accept many different data types, including JSON. Anything that makes connecting your data with your Power BI dashboard would be useful. Power BI's dashboard would be a nice clean look for displaying data. If you do make it, I would like to see it when it's done. Best of luck.
Not sure if your refering to the database password or the user example we made for the login form. We open the our connection to the data base with sql.Open("mysql", "root:super-secret-password@tcp(localhost:3306)/gin_db"). Here the user is named "root", keep in mind you will want to create different users for your database for different people with different permission levels, root can delete and do anything ,which is dangerous, only allow permissions for what is needed. The password used was "super-secret-password" which is meant to be humorous and educational about the fact that this should be a secret, and hard to guess, which this one is not. In production you would be storing passwords like these in system variables so that anyone who sees the source code can't just see the password being used. This was the password I used for setting up that particular database, if you used something different it will need to be whatever password you used. I don't remember the login password at the moment, it would be whatever you used to create the user account. If you can't remember the user password, you could try to reverse the hash back to a password, but it would probably be a lot easier to just delete that user and create a new one. Hope this was helpful, hope you make something great, cheers!
Gorilla and Gin have a lot of good tools for routing but Gin is easy to use for many more things like APIs, middleware chains, and more. I word searched the Gin package docs and didn't find the word "session". To get sessions you will need to import a package for it. This isn't really an issue since Gin makes middleware really easy. Gorilla does have 2.5K starts on Github but there are a lot of good packages out there for this. For instance I noticed that user appleboy on Github who has the 4th most commits on the Gin package also has the most commits on the package github.com/gin-contrib/sessions. I just might need to check this one out. Let me know what you think.
hello sir , thank u for this good tutorial I really find it better than a lot in the web , I wanna ask you if I should change my session package to gorilla actually I work right now with gin-contrib/session it lucks documentation and I'm always in problem with that just some small modification needs a lot of research and time consuming . Thank you
Thank you, I appreciate the complement. If the gin-contrib/sesssion package is working for you then I would stick with it. I believe I went with Gorilla since I was already familiar with it and there was more documentation at the time. You will need to check how much time you spend with the package, and it may be worth switching but usually not. If you do switch, there is always a small chance of running into its own little problems. Hope that was helpful.
@@GrowAdept glad to hear your response , actually the problems that I found is that the expired sessions in Mongodb doesn't get deleted so I have a lot of useless sessions making my db slow , so I made another solution for them TTL , and the implementation of HTTP only doesn't work fine I don't know if the problem in my code or the package since I did not found anything refer to this problem in google . Thank you so much sir
thank you, i need this one
Nice, glad it helped.
I see go video, i subscribed.
Glad you like the content, much appreciated.
very helpful thanks a lot
Glad to hear it was helpful, thank you. 😃
This is different than how I've handled sessions in other languages / toolchains (JS + Express, Python + Flask).
It looks like you're just putting the whole user object into the actual session cookie. Is putting data into the cookie like this not bad practice? if someone is able to guess a user ID and the shape of the user object would they not be able to fabricate a session token and login?
Typically I've seen session management systems create a sessions table that has 3 columns, session_id, user_id, and expires_at. This means you can 1) invalidate sessions you suspect have been highjacked and 2) have unique and hard to guess ID's for current sessions that aren't directly correlated to specific users. This is actually what seems to be in the diagram at the beginning of this video. Then your middleware just gets the session_id from your cookie, ensures it's still valid via expires_at, and then lets you do actions as the user in the user_id column.
Maybe I am missing something though? does gorilla sessions handle this sessions table for you in the background?
Very good question, I wish I had addressed this early in the video. Since all of the data is encrypted, a bad actor wouldn't know the shape of the struct/object, it's not encrypted field by field, the whole thing is encrypted. The cookie's encrypted data on the user's machine will appear as gibberish, unless decrypted of course. This is why a bad actor could social engineer someone in the company, get the shape of the struct/object and the user ID, but they still couldn't manufacture a response to impersonate the user. The cookie is signed, which the server checks, so bad actors would need to know that secret set by the server during the creation of the cookie. Also, the server decrypts the data from the cookie, changing it from what looked like gibberish to something more useful. So, the bad actor would need to know the encryption algorithm and the secret used during encryption by the server. This is why social engineering is so scary and why we go to great lengths to protect that secret. In later videos we save that secret in a system variable, so that way the secret isn't in our code which could accidentally get pushed to GitHub or leaked by almost everyone in the company. So, the secret used in production is only saved only the production machine, so we can greatly reduce the number of people who can see it to just those involved in pushing code into production.
So, Gorilla sessions does not save sessions in a sessions table on the server, so these cookies, like JSON web tokens, save session data on the client's side. Yes, at first this sounds scary, until we see the inner workings that make it light weight yet secure.
The auth function which authenticates our user's session. with the line: session, _ := store.Get(c.Request, "session"), will take the returned http request from the user. This will be decrypted and the signature in the cookie will be checked vs the key configured in the Gorilla sessions cookie store. So, if the cookie wasn't encrypted correctly, has expired or doesn't have the right secret key, then our session struct/object won't be returned into the variable named session. Which we need to have in the line _, ok := session.Values["user"] or else an error will be returned, and they will be sent back to the login page with the: if !ok {...} check.
Like I said, very good question, I wish I had explained the points you brought up more clearly. Thank you for bringing this to light as it will help others as well.
@@GrowAdept this is a really solid answer! Thank you for taking the time to respond. I've adopted the gorilla sessions package into a small go web app I'm building with the sessions table approach I described but your description addressed any concerns id have with the approach in this video which is definitely easier to manage!
Great video and thanks again for taking the time to address this!
That's great to hear, glad you found it helpful Feel free to share any projects Gin or Gorilla in the comments. It's always good to hear what people are building. I agree your approach will avoid problems with expiring sessions from bad actors in a stateless implementation, which is nice. If you ever feel your app will bump into the 4KB browser cookie storage limit with sessions, you might want to check out JSON web tokens which could get around 5MB. Happy coding and have a great day!
@@GrowAdept If you were an admin and wanted to change a value for the user in the DB like a usergroup for example, and you wanted this to reflect in the users data straight away you would need to update the users session data. How would you go about getting the users session to update it?
Video request, I am working on building a Go wrapper for Power BI rest API. Would love your take on the topic
I don't have much experience with Power BI but that does sound interesting. Gin makes a lot of the API work easier, and Power BI does accept many different data types, including JSON. Anything that makes connecting your data with your Power BI dashboard would be useful. Power BI's dashboard would be a nice clean look for displaying data. If you do make it, I would like to see it when it's done. Best of luck.
what password you are using here
Not sure if your refering to the database password or the user example we made for the login form.
We open the our connection to the data base with sql.Open("mysql", "root:super-secret-password@tcp(localhost:3306)/gin_db"). Here the user is named "root", keep in mind you will want to create different users for your database for different people with different permission levels, root can delete and do anything ,which is dangerous, only allow permissions for what is needed. The password used was "super-secret-password" which is meant to be humorous and educational about the fact that this should be a secret, and hard to guess, which this one is not. In production you would be storing passwords like these in system variables so that anyone who sees the source code can't just see the password being used. This was the password I used for setting up that particular database, if you used something different it will need to be whatever password you used.
I don't remember the login password at the moment, it would be whatever you used to create the user account. If you can't remember the user password, you could try to reverse the hash back to a password, but it would probably be a lot easier to just delete that user and create a new one.
Hope this was helpful, hope you make something great, cheers!
Why gin for routing and gorilla sessions for sessions? Why not to use gin for both or gorilla for both?
Gorilla and Gin have a lot of good tools for routing but Gin is easy to use for many more things like APIs, middleware chains, and more. I word searched the Gin package docs and didn't find the word "session". To get sessions you will need to import a package for it. This isn't really an issue since Gin makes middleware really easy. Gorilla does have 2.5K starts on Github but there are a lot of good packages out there for this. For instance I noticed that user appleboy on Github who has the 4th most commits on the Gin package also has the most commits on the package github.com/gin-contrib/sessions. I just might need to check this one out. Let me know what you think.
hello sir , thank u for this good tutorial I really find it better than a lot in the web , I wanna ask you if I should change my session package to gorilla actually I work right now with gin-contrib/session it lucks documentation and I'm always in problem with that just some small modification needs a lot of research and time consuming .
Thank you
Thank you, I appreciate the complement. If the gin-contrib/sesssion package is working for you then I would stick with it. I believe I went with Gorilla since I was already familiar with it and there was more documentation at the time. You will need to check how much time you spend with the package, and it may be worth switching but usually not. If you do switch, there is always a small chance of running into its own little problems. Hope that was helpful.
@@GrowAdept glad to hear your response , actually the problems that I found is that the expired sessions in Mongodb doesn't get deleted so I have a lot of useless sessions making my db slow , so I made another solution for them TTL , and the implementation of HTTP only doesn't work fine I don't know if the problem in my code or the package since I did not found anything refer to this problem in google . Thank you so much sir