Sessions: Toko Pihak Ketiga Tidak Menerapkan Opsi ke Codec dengan benar.

Dibuat pada 10 Jul 2015  ·  17Komentar  ·  Sumber: gorilla/sessions

Kami baru saja memutakhirkan paket ini dan tidak mengatur cookie dengan benar. Ini mengatur hal-hal seperti _ga=GA1.1.922831813.14264788986 alih-alih data cookie yang disandikan base64 biasa. Adakah yang tahu apa yang terjadi atau kapan ini rusak sehingga kami dapat kembali ke versi yang berfungsi? Terima kasih!

bug stale

Komentar yang paling membantu

Perhatikan bahwa ini juga memengaruhi sebagian besar implementasi toko, karena semuanya menggunakan securecookie untuk menyimpan ID ke toko backend mereka.

redistore memiliki setengah dari implementasi yang benar jika Anda memanggil SetMaxAge secara manual tetapi tidak secara langsung menerapkan ini untuk kasus default. Kebetulan default (30 hari) sama dengan securecookie.

Dari sekilas tampak bahwa _semua_ toko lain terpengaruh—pengaturan MaxAge melalui struct Opsi tidak diterapkan ke instance securecookie yang mendasari yang dihasilkan dari CodecsFromPairs. Sebagian besar pengguna akhir tidak akan mengalami bug ini karena saya menduga sebagian besar pengguna menetapkan tanggal kedaluwarsa _less_ daripada apa yang secara implisit disematkan securecookie ke HMAC.

FWIW: Saya juga percaya bahwa kedaluwarsa cookie "jauh di masa depan" tidak bagus kecuali Anda memiliki kebutuhan yang sangat spesifik untuk itu.

Semua 17 komentar

Cookie "_ga" tidak terkait dengan gorila/sesi - ini adalah Google Analytics
Kue kering.

Jika gorila/sesi tidak mengatur cookie (belum ada kerusakan
perubahan) dapatkah Anda memposting kode yang relevan dan output dari panel Cookies?
dari peramban Anda? (inspektur > sumber daya > cookie di bawah Chrome)

Pada Jum, 10 Jul 2015 jam 07:12 markalpeter [email protected]
menulis:

Kami baru saja memutakhirkan paket ini dan tidak mengatur cookie dengan benar. Nya
mengatur hal-hal seperti _ga=GA1.1.922831813.14264788986 alih-alih yang biasa
data cookie yang disandikan base64. Tahu apa yang terjadi atau kapan ini pecah jadi broke
kita dapat kembali ke versi kerja? Terima kasih!


Balas email ini secara langsung atau lihat di GitHub
https://github.com/gorilla/sessions/issues/48.

Hai Matt,

Saya juga sedang mengerjakan proyek dengan Mark dan saya dapat memberi Anda beberapa detail lebih lanjut. Jadi kami baru saja memperbarui paket karena masalah aslinya adalah semua cookie kedaluwarsa setelah 30 hari bahkan ketika kami mengatur MaxAge ke jumlah yang sangat besar. Berikut adalah kode Otentikasi yang aktif saat ini dan menyebabkan masalah bagi kami:

konstan (
AUTH_SESSION_NAME = "sesi otentikasi"
)

var (
config = jconfig.LoadConfig( global.CONFIG() + "securecookie.json" )
authKey = []byte(config.GetString("authorization_key"))
enkripsiKey = []byte(config.GetString("encryption_key"))
session = session.NewCookieStore(authKey, enkripsiKey)
)

fungsi init() {

apiRouter.HandleFunc("/auth/"   , Authenticate      )
apiRouter.HandleFunc("/deauth/"  , Deauthenticate   )
apiRouter.HandleFunc("/reauth/" , ReAuthenticate    )

// register complex data types for saving in sessions
gob.Register(&models.Device{})
gob.Register(&models.Manager{})
gob.Register(&models.SalesRep{})

// modify the options of the session store so that the auth cookie never expires (this is set so it expires in 200 years...)
session.Options.MaxAge = 6307200000

}

// handler ini memberikan izin dalam sistem untuk perangkat dan manajer
// jika pemohon sudah diotorisasi, itu akan menampilkan informasi mereka. Untuk mengesahkan suatu deferent
// akun, pertama klien harus melakukan deauthenticate.
//
// Param
// pengguna:
//
// catatan: data yang dikembalikan dari fungsi auth ini hanya dijamin akurat
// saat pengguna pertama kali mengautentikasi. jika tidak, itu akan menampilkan data yang di-cache di sesi mereka
//
func Otentikasi(respons http.ResponseWriter, request *http.Request) {

log.Println("Authenticate")

// open the session
auth_session, err :=  session.Get(request, AUTH_SESSION_NAME)
if err != nil {
    log.Println("there was an error retreiving the session:", err)
    InternalServerError(response, request)
    return
}

// already authroized as a manager
if manager, ok := auth_session.Values["manager"].(*models.Manager); ok {
    log.Printf("already logged in as manager %d", manager.Id)
    Success(response, request, manager)

// already authrorized as a device
} else if device, ok := auth_session.Values["device"].(*models.Device); ok {
    log.Printf("already logged in as device %d", device.Id)
    Success(response, request, device)

// attempt to gain authroization
} else {            
    fp  := parsers.FormParser(request)  

    // login as a manager
    if username, password := fp.GetString("user", ""), fp.GetString("pass", ""); username != "" && password != ""  {

        db := database.Open()
        defer db.Close()


        if manager := db.LoginAsManager(username, password); manager != nil {
            auth_session.Values["manager"] = manager

            // manager session error
            if err := auth_session.Save(request, response); err != nil {
                log.Printf("manager could not save session %s !\n", err.Error())
                InternalServerError(response, request)

            // manager login in success
            } else {
                log.Printf("logged in as manager %d !\n", manager.Id)
                Success(response, request, manager)     
            }

        // manager login failed
        } else {
            log.Printf("manager credentials not valid!")
            Unauthroized(response, request)
        }

    // login as a salesrep
    } else if username, password := fp.GetString("username", ""), fp.GetString("password", ""); username != "" && password != "" {

        db := database.Open()
        defer db.Close()


        if sales_rep_id := db.LoginAsSalesRep(username, password); sales_rep_id > 0 {

            sales_reps := db.GetSalesRep(&models.SalesRep{ Id: sales_rep_id });

            auth_session.Values["sales_rep"] = sales_reps[0];

            // sales rep session error
            if err := auth_session.Save(request, response); err != nil {
                log.Printf("sales rep could not save session %s !\n", err.Error())
                InternalServerError(response, request)

            // sales rep login in success
            } else {
                log.Printf("logged in as sales rep %d !\n", manager.Id)
                Success(response, request, manager)     
            }

        // sales rep login failed
        } else {
            log.Printf("sales rep credentials not valid!")
            Unauthroized(response, request)
        }

    // login as a device
    } else if pin_code := fp.GetInt32("PinCode", -1); pin_code > 0 {

        db := database.Open()
        defer db.Close()

        if devices := db.GetDevice(&models.Device{ PinCode:pin_code }, nil); len(devices) > 0 {
            auth_session.Values["device"] = &devices[0]

            // device session error
            if err := auth_session.Save(request, response); err != nil {
                log.Printf("device could not save session %s !\n", err.Error())
                InternalServerError(response, request)

            // device login in success
            } else {
                log.Printf("logged in as device %d !\n", devices[0].Id)
                Success(response, request, devices[0])      
            }

        // device login failed
        } else {
            log.Printf("device credentials not valid!")
            Unauthroized(response, request)
        }


    // no valid credentials were provided   
    } else {
        log.Println("no valid deivce or manager credentials")
        BadRequest(response, request)
    }

}

}

Dan inilah yang kami dapatkan di log setelah 30 hari:

Cookie Perangkat: sesi otentikasi=_KaJDVq4lIdQgeHiHcnSMw1IEPDyg3-9XEIBBPxw==; Jalur=/; Kedaluwarsa=Senin, 15 Mei 2215 20:47:49 UTC; Usia Maks = 63072000000

2015/07/10 15:56:04 /routers/api/Auth.go:70: securecookie: stempel waktu kedaluwarsa

Semua cookie tampaknya kedaluwarsa setelah 30 hari terlepas dari apa yang kami tetapkan untuk MaxAge. Setiap bantuan Anda sangat besar bagi kami. Terima kasih!

Baiklah, saya telah mengolok-olok program demo minimal di mana saya menetapkan MaxAge di seluruh toko menjadi 2 bulan (86400 * 60):

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte("some-appropriately-auth-key"))

func SomeHandler(w http.ResponseWriter, r *http.Request) {
    session, err := store.Get(r, "example")
    if err != nil {
        http.Error(w, "No good!", 500)
        return
    }

    session.Values["gorilla"] = "sessions!"
    err = session.Save(r, w)
    if err != nil {
        http.Error(w, "No good!", 500)
        return
    }

    fmt.Fprintf(w, "%v", session.Values["gorilla"])
}

func main() {
    store.Options = &sessions.Options{
        MaxAge: 86400 * 60, // 2 months
    }

    http.HandleFunc("/", SomeHandler)
    log.Fatal(http.ListenAndServe(":8002", nil))
}

Ini memberi saya waktu kedaluwarsa yang saya harapkan:

Expiry time test

Menyetel jam saya secara manual ke depan ~33 hari juga membuat saya mendapatkan kesalahan expired timestamp dari securecookie - yang salah.

Menghapus cookie di browser, mengatur ulang jam kembali ke now() dan kemudian memaksa MaxAge pada *securecookie.SecureCookie mendasarinya melalui yang berikut:

    store.Options = &sessions.Options{
        MaxAge: 86400 * 60, // 2 months
    }
    for _, s := range store.Codecs {
        if cookie, ok := s.(*securecookie.SecureCookie); ok {
            cookie.MaxAge(86400 * 90)
        }
    }

Ini masih memberi saya cookie browser dengan kedaluwarsa +2 bulan ke depan karena bidang maxAge dari setiap codec tidak memengaruhi apa yang dilihat browser saat kita menulis http.Cookie . Namun, menyetel jam saya +33 hari ke depan tidak menghasilkan kesalahan cap waktu yang kedaluwarsa.

Jadi saya melakukan penggalian:

TL;DR : Akar penyebabnya adalah http.Cookie ditulis ke browser mendapatkan stempel waktu yang kami tetapkan dalam opsi kami, tetapi HMAC untuk instance securecookie yang mendasarinya adalah gabungan dari date|value|mac - di mana tanggal _default_ MaxAge yang tidak diperbaiki oleh Opsi kami. Validasi HMAC kemudian gagal setelah kami mencapai > 30 hari.

Perbaikannya adalah untuk sessions.NewCookieStore berkisar pada codec yang dibuatnya dan menerapkan Options.MaxAge ke setiap instance *securecookie.SecureCookie untuk memungkinkannya mengoreksi ketidakcocokan antara kedaluwarsa cookie dan validasi stempel waktu HMAC.

cc/ @kisielk untuk memvalidasi temuan saya sebelum saya melakukan perbaikan.

PS: Tidak terkait dengan ini, praktik terbaik untuk membuka satu kumpulan DB di program Anda, baik itu melalui global atau dengan secara eksplisit memberikan pointer. Membuka dan menutup kumpulan per-permintaan memiliki kinerja yang baik. *sql.DB aman untuk akses bersamaan.

Perhatikan bahwa ini juga memengaruhi sebagian besar implementasi toko, karena semuanya menggunakan securecookie untuk menyimpan ID ke toko backend mereka.

redistore memiliki setengah dari implementasi yang benar jika Anda memanggil SetMaxAge secara manual tetapi tidak secara langsung menerapkan ini untuk kasus default. Kebetulan default (30 hari) sama dengan securecookie.

Dari sekilas tampak bahwa _semua_ toko lain terpengaruh—pengaturan MaxAge melalui struct Opsi tidak diterapkan ke instance securecookie yang mendasari yang dihasilkan dari CodecsFromPairs. Sebagian besar pengguna akhir tidak akan mengalami bug ini karena saya menduga sebagian besar pengguna menetapkan tanggal kedaluwarsa _less_ daripada apa yang secara implisit disematkan securecookie ke HMAC.

FWIW: Saya juga percaya bahwa kedaluwarsa cookie "jauh di masa depan" tidak bagus kecuali Anda memiliki kebutuhan yang sangat spesifik untuk itu.

Saya juga ingin menunjukkan bahwa cap waktu saat ini benar-benar tidak terenkripsi dalam implementasi saat ini. Saya bisa, secara teoritis, base64 mendekode cookie, mengubah stempel waktu ke hari ini, base64 menyandikan cookie, dan kemudian properti MaxAge tidak masalah sama sekali, bahkan jika Anda memperbaiki opsi.MaxAge masalah.

Ya, cookie "masa depan yang jauh" hanya untuk pengujian, kami memiliki MaxAge yang disetel ke 0 di server produksi kami sekarang. Kami menemukan masalah selama akhir pekan dan menulis perbaikan serupa, tetapi sedikit kurang ringkas dari Anda.

Terima kasih telah menyelidiki masalah ini!

@wbaron - tidak ada masalah. Kami akan segera memperbaikinya di paket upstream dan
Saya akan ping Anda setelah selesai sehingga Anda tidak perlu memelihara garpu Anda sendiri (jika Anda
tidak mau).

@marksalpeter - Bisakah Anda menunjukkan di mana? securecookie MACs
name|date|value sebelum base64 menyandikannya untuk representasi string. Jika
Anda memecahkan kode di sisi klien, Anda tidak dapat mengubah stempel waktu di sana (itu
MAC'ed—tidak ada yang benar-benar dapat Anda mod) dan jika Anda mencobanya,
cookie harus gagal validasi pada decode (permintaan) karena MAC akan gagal
untuk memecahkan kode dengan benar terhadap kunci hash/auth. Referensi:
https://github.com/gorilla/securecookie/blob/master/securecookie.go#L185 -L191

Pada Selasa, 14 Juli 2015 pukul 22:40 wbaron [email protected] menulis:

Ya, cookie "masa depan yang jauh" hanya untuk pengujian, kami memiliki MaxAge yang disetel ke
0 di server produksi kami sekarang. Kami menemukan masalah selama akhir pekan dan
menulis perbaikan yang mirip dengan milik Anda, dengan sedikit lebih ringkas.

Terima kasih telah menyelidiki masalah ini!


Balas email ini secara langsung atau lihat di GitHub
https://github.com/gorilla/sessions/issues/48#issuecomment -121257995.

@elithrar kesalahan saya. ketika saya memecahkan kode cookie saya mendapatkan [timestamp]|[MAC'ed info] Saya hanya berasumsi bahwa cap waktu sebelum info maks adalah yang Anda gunakan.

@elithrar apa yang Anda usulkan terdengar bagus untuk saya. Malu bahwa itu harus diterapkan ke setiap toko secara individual :/

@kisielk - Pasti memalukan. Saya ingin menghindari menyentuh pihak ketiga
toko tetapi tidak ada cara yang bersih untuk secara efektif memasangkan toko pihak ketiga
Bidang Options.MaxAge dengan metode s.MaxAge di securecookie.

Saya sedang mempertimbangkan untuk menyediakan fungsi func CodecMaxAge(codecs []Codec, age int) []Codec di securecookie (kelemahan: tidak dapat menjadi metode pada
interface + menambahkan ke API publik) yang secara internal melakukan tipe
pernyataan + panggilan s.MaxAge(age) pada setiap Codec. Ini terus berlebihan (loop
over slice, ketik assert to cookie type) kode dari toko pihak ketiga
karena mereka hanya perlu memanggil securecookie.CodecMaxAge(mystore.Codecs, mystore.opts.MaxAge) dalam fungsi NewXXXXStore untuk mengatur
bidang s.maxAge yang mendasarinya.

Terbuka untuk ide-ide yang lebih baik tetapi ini tampaknya yang paling sederhana.

Pada Jum, 17 Jul 2015 jam 8:03 Kamil Kisiel [email protected]
menulis:

@elithrar https://github.com/elithrar apa yang Anda usulkan terdengar bagus untuk
saya. Malu bahwa itu harus diterapkan ke setiap toko secara individual :/


Balas email ini secara langsung atau lihat di GitHub
https://github.com/gorilla/sessions/issues/48#issuecomment -122133977.

Ya saya pikir baik-baik saja. Saya akan mengirimkan beberapa PR ke toko lain untuk menggunakannya setelah Anda mendapatkan kembaliannya di sini.

Untuk tujuan pelacakan:

  • [x] [gorilla/sessions](https://github.com/gorilla/sessions)
  • [ ] [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB
  • [ ] [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Baut
  • [ ] [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
  • [ ] [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb di AWS
  • [ ] [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
  • [ ] [github.com/hnakamur/gaesessions](https://github.com/hnakamur/gaesessions) - Memcache di GAE
  • [x] [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
  • [ ] [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
  • [x] [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
  • [ ] [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
  • [x] [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
  • [ ] [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
  • [ ] [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite

Saya akan melacak ini setelah PR digabungkan.

Masalah ini secara otomatis ditandai sebagai basi karena belum melihat pembaruan terbaru. Ini akan ditutup secara otomatis dalam beberapa hari.

Melihat masalah ini setelah menjalankannya dari paket lain, sepertinya tidak harus ditutup... Daftar periksa @elithrar masih membutuhkan 10 pemeriksaan lagi, kecuali informasi itu kedaluwarsa.

Itu harus akurat: tetapi tidak semua toko dipelihara secara aktif atau memiliki PR yang dikirimkan.

Masalah ini secara otomatis ditandai sebagai basi karena belum melihat pembaruan terbaru. Ini akan ditutup secara otomatis dalam beberapa hari.

Masalah ini secara otomatis ditandai sebagai basi karena belum melihat pembaruan terbaru. Ini akan ditutup secara otomatis dalam beberapa hari.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

gtaylor picture gtaylor  ·  7Komentar

cless picture cless  ·  23Komentar

luca-moser picture luca-moser  ·  3Komentar

elithrar picture elithrar  ·  25Komentar

CasperHK picture CasperHK  ·  11Komentar