kataras / iris

The fastest HTTP/2 Go Web Framework. New, modern and easy to learn. Fast development with Code you control. Unbeatable cost-performance ratio :rocket:
https://www.iris-go.com
BSD 3-Clause "New" or "Revised" License
25.29k stars 2.47k forks source link

session cookie CookieSecureTLS only if request is TLS #1490

Closed mblaschke closed 4 years ago

mblaschke commented 4 years ago

Describe the bug If the application is running behind a TLS offloader (eg. in K8s secured with a ServiceMesh) the request to the application is made with plain HTTP so the cookie is never set secure. There should be a possibility to enforce this value.

Same for the cookie domain, which is currently extracted dynamically and it should be able to set it to a static value.

To Reproduce Steps to reproduce the behavior:

  1. run application behind a TLS offloader
  2. cookie is not secure

Expected behavior Cookie should be secure regardless from the TLS status of the request

Desktop (please complete the following information):

Additional context see https://github.com/kataras/iris/blob/v12/sessions/sessions.go#L66

kataras commented 4 years ago

Hello @mblaschke, there is a possibility to enforce this value by setting a CookieOption: second variadic parameter of sessions.Start or the first variadic parameter of sessManager.Handler*.

Example Code:

sess := sessions.New(...)
sess.Handler(func(cookie *http.Cookie){
    cookie.Secure = true
})

About your statement of:

Cookie should be secure regardless from the TLS status of the request

This is not true and shouldn't be set. Starting with Chrome 52 and Firefox 52, insecure sites (http:) can't set cookies with the Secure directive. So, I mark this issue as a question instead, it's not a bug. If you need more information please don't hesitate to post below.

Thanks, Gerasimos Maropoulos

mblaschke commented 4 years ago

Cookie should be secure regardless from the TLS status of the request

This statement was only for this use case, not generally :)

But thanks for the solution, will try it.. currently I'm struggling with the handler. It works for the internal session handling if I pass it with session.Start() but not with the sessManager.Handler.

If i'm using the Redis session (github.com/kataras/iris/v12/sessions/sessiondb/redis) it's not working at all 🤔

    sess := c.session.Start(ctx, func(cookie *http.Cookie){
        fmt.Println("cookie handler called")
        cookie.Secure = true
    })

with redis the handler is not called.

kataras commented 4 years ago

No @mblaschke, it's working fine here. Try to remove the cookies from the client and try again. Tested with latest redis (windows) and clients: Postman, Chrome, Firefox and Edge. In order to use Secure you need to fire the server from https as explained above. See the Secure; field on the Set-Cookie below:

set

get

get

redis

image

Example Code:

package main

import (
    "errors"
    "net/http"
    "time"

    "github.com/kataras/iris/v12"

    "github.com/kataras/iris/v12/sessions"
    "github.com/kataras/iris/v12/sessions/sessiondb/redis"
)

func main() {
    // These are the default values,
    // you can replace them based on your running redis' server settings:
    db := redis.New(redis.Config{
        Network:   "tcp",
        Addr:      "127.0.0.1:6379",
        Timeout:   time.Duration(30) * time.Second,
        MaxActive: 10,
        Password:  "",
        Database:  "",
        Prefix:    "",
        Delim:     "-",
        Driver:    redis.Redigo(), // redis.Radix() can be used instead.
    })

    // Close connection when control+C/cmd+C
    iris.RegisterOnInterrupt(func() {
        db.Close()
    })

    sess := sessions.New(sessions.Config{
        Cookie:       "sessionscookieid",
        Expires:      0,
        AllowReclaim: true,
                 /* If set to true and TLS, then cookie option can be removed */
                CookieSecureTLS: false, 
    })
    sess.UseDatabase(db)

    // the rest of the code stays the same.
    app := iris.New()
    app.Use(sess.Handler(func(c *http.Cookie) {
                // or CookieSecureTLS: true on the sessions configuration.
        c.Secure = true 
    }))

    app.Get("/set", func(ctx iris.Context) {
        session := sessions.Get(ctx)
        // set session values
        session.Set("name", "iris")

        // test if set here
        ctx.Writef("All ok session value of the 'name' is: %s", session.GetString("name"))
    })

    app.Get("/get", func(ctx iris.Context) {
        session := sessions.Get(ctx)
        name := session.GetString("name")

        ctx.Writef("The 'name' on the /set was: %s", name)
    })

    app.Listen(":8080", iris.WithTunneling)
}

In order to test it you may want to enable the iris.WithTunneling, create account or login to ngrok and add the executable to your $PATH.

Otherwise, Secure is correctly pushed to the Set-Cookie response header but you can't retrieve it from http request. See below:

image

Tested with iris-master branch.

mblaschke commented 4 years ago

Ok, now it's working. Thanks!

I though the handler is something like the app.Use handlers.

so i was wondering why this wasn't working:

       sess.Handler(func(c *http.Cookie) {
        c.Secure = true 
    })
        c.app.Use(c.session.Handler())

i was blind but thanks for your example, that helped a lot to find the issue :)