iris/sessions
2016-06-30 05:58:04 +03:00
..
providers Embrace the weekend- Update to rc.3 | Read the HISTORY.md 2016-06-24 01:34:49 +03:00
store Version 3.0.0-beta cleaned 2016-05-30 17:08:09 +03:00
errors.go Embrace the weekend- Update to rc.3 | Read the HISTORY.md 2016-06-24 01:34:49 +03:00
manager.go Fix https://github.com/kataras/iris/issues/231 2016-06-30 05:58:04 +03:00
provider.go Version 3.0.0-beta cleaned 2016-05-30 17:08:09 +03:00
README.md Version 3.0.0-beta cleaned 2016-05-30 17:08:09 +03:00
sessions.go Update to 3.0.0-rc.1 - Read the HISTORY.md. Relative: #183 #184 #166 #176 #181 2016-06-14 08:45:40 +03:00

Folder Information

This folder contains the sessions support for Iris. The folder name is plural (session's') so the /sessions/providers, because you can use both of them at the same time.

Package information

This package is new and unique, if you notice a bug or issue post it here.

  • Cleans the temp memory when a sessions is iddle, and re-loccate it , fast, to the temp memory when it's necessary. Also most used/regular sessions are going front in the memory's list.

  • Supports redisstore and normal memory routing. If redisstore is used but fails to connect then ,automatically, switching to the memory storage.

A session can be defined as a server-side storage of information that is desired to persist throughout the user's interaction with the web site or web application.

Instead of storing large and constantly changing information via cookies in the user's browser, only a unique identifier is stored on the client side (called a "session id"). This session id is passed to the web server every time the browser makes an HTTP request (ie a page link or AJAX request). The web application pairs this session id with it's internal database/memory and retrieves the stored variables for use by the requested page.


You will see two different ways to use the sessions, I'm using the first. No performance differences.

How to use - easy way

Example memory


package main

import (
	"github.com/kataras/iris"
)

func main() {

	// these are  the defaults
	//iris.Config().Session.Provider = "memory"
	//iris.Config().Session.Secret = "irissessionid"
	//iris.Config().Session.Life = time.Duration(60) *time.Minute

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}


Example default redis


package main

import (
	"github.com/kataras/iris"
)

func main() {

	iris.Config().Session.Provider = "redis"

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}

Example customized redis

// Config the redis config
type Config struct {
	// Network "tcp"
	Network string
	// Addr "127.0.01:6379"
	Addr string
	// Password string .If no password then no 'AUTH'. Default ""
	Password string
	// If Database is empty "" then no 'SELECT'. Default ""
	Database string
	// MaxIdle 0 no limit
	MaxIdle int
	// MaxActive 0 no limit
	MaxActive int
	// IdleTimeout 5 * time.Minute
	IdleTimeout time.Duration
	// Prefix "myprefix-for-this-website". Default ""
	Prefix string
	// MaxAgeSeconds how much long the redis should keep the session in seconds. Default 2520.0 (42minutes)
	MaxAgeSeconds int
}


package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions/providers/redis"
)

func init() {
	redis.Config.Addr = "127.0.0.1:2222"
	redis.Config.MaxAgeSeconds = 5000.0
}

func main() {

	iris.Config().Session.Provider = "redis"

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}

How to use - hard way

// New creates & returns a new Manager and start its GC
// accepts 4 parameters
// first is the providerName (string) ["memory","redis"]
// second is the cookieName, the session's name (string) ["mysessionsecretcookieid"]
// third is the gcDuration (time.Duration)
// when this time passes it removes from
// temporary memory GC the value which hasn't be used for a long time(gcDuration)
// this is for the client's/browser's Cookie life time(expires) also

New(provider string, cName string, gcDuration time.Duration) *sessions.Manager

Example memory


package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

	_ "github.com/kataras/iris/sessions/providers/memory" // here we add the memory provider and store
)

var sess *sessions.Manager

func init() {
	sess = sessions.New("memory", "irissessionid", time.Duration(60)*time.Minute)
}

func main() {

	iris.Get("/set", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		//set session values
		session.Set("name", "kataras")

		//test if setted here
		c.Write("All ok session setted to: %s", session.Get("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		var name string

		//get the session value
		if v := session.Get("name"); v != nil {
			name = v.(string)
		}
		// OR just name = session.GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

		iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		session.Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)
		// removes all entries
		session.Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		sess.Destroy(c)
	})

	iris.Listen("8080")
}

// session.GetAll() returns all values a map[interface{}]interface{}
// session.VisitAll(func(key interface{}, value interface{}) { /* loops for each entry */})

}



Example redis with default configuration

The default redis client points to 127.0.0.1:6379


package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

	_ "github.com/kataras/iris/sessions/providers/redis"
    // here we add the redis  provider and store
    //with the default redis client points to 127.0.0.1:6379
)

var sess *sessions.Manager

func init() {
	sess = sessions.New("redis", "irissessionid", time.Duration(60)*time.Minute)
}

//... usage: same as memory

Example redis with custom configuration

type Config struct {
	// Network "tcp"
	Network string
	// Addr "127.0.01:6379"
	Addr string
	// Password string .If no password then no 'AUTH'. Default ""
	Password string
	// If Database is empty "" then no 'SELECT'. Default ""
	Database string
	// MaxIdle 0 no limit
	MaxIdle int
	// MaxActive 0 no limit
	MaxActive int
	// IdleTimeout 5 * time.Minute
	IdleTimeout time.Duration
	//Prefix "myprefix-for-this-website". Default ""
	Prefix string
	// MaxAgeSeconds how much long the redis should keep the session in seconds. Default 2520.0 (42minutes)
	MaxAgeSeconds int
}
package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

     "github.com/kataras/iris/sessions/providers/redis"
    // here we add the redis  provider and store
    //with the default redis client points to 127.0.0.1:6379
)

var sess *sessions.Manager

func init() {
    // you can config the redis after init also, but before any client's request
    // but it's always a good idea to do it before sessions.New...
    redis.Config.Network = "tcp"
    redis.Config.Addr = "127.0.0.1:6379"
    redis.Config.Prefix = "myprefix-for-this-website"

	sess = sessions.New("redis", "irissessionid", time.Duration(60)*time.Minute)
}

//...usage: same as memory

Security: Prevent session hijacking

This section is external

cookie only and token

Through this simple example of hijacking a session, you can see that it's very dangerous because it allows attackers to do whatever they want. So how can we prevent session hijacking?

The first step is to only set session ids in cookies, instead of in URL rewrites. Also, we should set the httponly cookie property to true. This restricts client side scripts that want access to the session id. Using these techniques, cookies cannot be accessed by XSS and it won't be as easy as we showed to get a session id from a cookie manager.

The second step is to add a token to every request. Similar to the way we dealt with repeat forms in previous sections, we add a hidden field that contains a token. When a request is sent to the server, we can verify this token to prove that the request is unique.

h := md5.New()
salt:="secret%^7&8888"
io.WriteString(h,salt+time.Now().String())
token:=fmt.Sprintf("%x",h.Sum(nil))
if r.Form["token"]!=token{
    // ask to log in
}
session.Set("token",token)

Session id timeout

Another solution is to add a create time for every session, and to replace expired session ids with new ones. This can prevent session hijacking under certain circumstances.


createtime := session.Get("createtime")
if createtime == nil {
    session.Set("createtime", time.Now().Unix())
} else if (createtime.(int64) + 60) < (time.Now().Unix()) {
    sess.Destroy(c)
    session = sess.Start(c)
}

We set a value to save the create time and check if it's expired (I set 60 seconds here). This step can often thwart session hijacking attempts.

Combine the two solutions above and you will be able to prevent most session hijacking attempts from succeeding. On the one hand, session ids that are frequently reset will result in an attacker always getting expired and useless session ids; on the other hand, by setting the httponly property on cookies and ensuring that session ids can only be passed via cookies, all URL based attacks are mitigated.