Sessions & Cookies

In this section we will learn how to configure Session cookies (and general HTTP cookies) in a more security-perspective view.

Disable Subdomain Persistence

By default Iris Sessions Manager allows cookie sharing between your root domain and subdomains, for security reasons you may want to disable that behavior with the DisableSubdomainPersistence option:

import "github.com/kataras/iris/v12/sessions"
sess := sessions.New(sessions.Config{
    Cookie: "_iris_session",
    AllowReclaim: true,
    DisableSubdomainPersistence: true,
})
app.UseRouter(sess.Handler())

The Sessions Manager has its own field to configure the session cookie encryption in order to be independent from other cookies sent to the client. You can pass Cookie Options at the sess.Handler(...CookieOption) method too.

Contrariwise, the default cookie options have disabled the cookie sharing across subdomains. When working with HTTP cookies, the SameSite option should be set to http.SameSiteLaxMode and its Domain field to the current site domain in order to enable cookie sharing under a root domain and its subdomains. You can do it by setting the CookieAllowSubdomains Cookie Option to the Iris request Context:

CookieAllowSubdomains(cookieNames ...string) CookieOption
func routeHandler(ctx iris.Context) {
    ctx.SetCookieKV("name", "value", iris.CookieAllowSubdomains())
}
import "net/http"
// [...]

func routeHandler(ctx iris.Context) {
    ctx.SetCookie(&iris.Cookie{
        Name: "name",
        Value: "value",
        // Other Fields...
    }, iris.CookieAllowSubdomains())
}

Or by using the AddCookieOptions.

func middleware(ctx iris.Context) {
    ctx.AddCookieOptions(iris.CookieAllowSubdomains())
    ctx.Next()
}

func routeHandler(ctx iris.Context) {
    ctx.SetCookieKV("name", "value")
}

func main() {
    app := iris.New()
 
    app.Use(middleware)
    app.Get("/", routeHandler)
    // [...]
}

Like the CSRF token, we learnt about in the previous sections, you can also secure all cookies in general.

The iris.CookieEncoding option registers a SecureCookie implementation.

CookieEncoding(encoding SecureCookie, cookieNames ...string) CookieOption

The SecureCookie interface looks like this:

type SecureCookie interface {
    Encode(name string, val interface{}) (string, error)
    Decode(name string, original string, dest interface{}) error
}

The SecureCookie interface is 100% compatible with the gorilla/securecookie package. Which is simple and easy to use and it does its job very good.

Let's see how we can integrate it with Iris to safely transmit our cookies to clients. Note that, it's still highly recommended your server runs under TLS (https://).

1. Install the securecookie package:

$ go get -u github.com/gorilla/securecookie

2. Import it in your code:

import "github.com/gorilla/securecookie"

3. The securecookie requires hash and block keys, should be NOT shared publically. For the sake of the example we will use generated ones but, keep note that the keys should be persistence across server restarts in production stage in order for cookies to be validated as expected:

hashKey  := securecookie.GenerateRandomKey(64)
blockKey := securecookie.GenerateRandomKey(32)

4. Initialize a secure cookie instance:

s := securecookie.New(hashKey, blockKey)

5. Register it with the Iris CookieEncoding Option, as we've seen below there are several ways, depending when and where you need a cookie option to be applied:

import "net/http"
// [...]

func routeHandler(ctx iris.Context) {
    ctx.SetCookie(&iris.Cookie{
        Name: "name",
        Value: "value",
    }, iris.CookieEncoding(s))
}

func main() {
    app := iris.New()

    app.Get("/", routeHandler)
    // [...]
}

OR to register it on all cookies, using a middleware and calling the AddCookieOption Context method:

func routeHandler(ctx iris.Context) {
    ctx.SetCookie(&iris.Cookie{
        Name: "name",
        Value: "value",
    })
}

func main() {
    app := iris.New()
    app.UseRouter(func(ctx iris.Context) {
        ctx.AddCookieOptions(iris.CookieEncoding(s))
        ctx.Next()
    })

    app.Get("/", routeHandler)
    // [...]
}

The introduction of the SameSite attribute (defined in RFC6265) allows you to declare if your cookie should be restricted to a first-party or same-site context. It's helpful to understand exactly what 'site' means here. The site is the combination of the domain suffix and the part of the domain just before it. For example, the www.web.dev domain is part of the web.dev site.

If the user is on www.web.dev and requests an image from static.web.dev then that is a same-site request.

The public suffix list defines this, so it's not just top-level domains like .com but also includes services like github.io. That enables your-project.github.io and my-project.github.io to count as separate sites.

If the user is on your-project.web.dev and requests an image from my-project.github.io that's a cross-site request.

Introducing the SameSite attribute on a cookie provides three different ways to control this behaviour. You can choose to not specify the attribute, or you can use Strict or Lax to limit the cookie to same-site requests.

The SameSite attribute accepts three values:

  • Lax Cookies are allowed to be sent with top-level navigations and will be sent along with GET request initiated by third party website. This is the default value in modern browsers.

  • Strict Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites.

  • None Cookies will be sent in all contexts, i.e sending cross-origin is allowed. None used to be the default value, but recent browser versions made Lax the default value to have reasonably robust defense against some classes of cross-site request forgery (CSRF) attacks. None requires the Secure attribute in latest browser versions.

Available Cookie SameSite Values:

  • iris.SameSiteDefaultMode

  • iris.SameSiteLaxMode

  • iris.SameSiteStrictMode

  • iris.SameSiteNoneMode

Set SameSite with SetCookie:

ctx.SetCookie(&iris.Cookie{
    Name: ...,
    Value: ...,
    SameSite: iris.SameSiteLaxMode,
})

Set SameSite with AddCookieOptions:

ctx.AddCookieOptions(iris.CookieSameSite(iris.SameSiteLaxMode))

Set SameSite with SetCookieKV:

ctx.SetCookieKV(name, value, iris.CookieSameSite(iris.SameSiteLaxMode))

Last updated