Sessions: متاجر الطرف الثالث لا تطبق الخيارات على برامج الترميز بشكل صحيح.

تم إنشاؤها على ١٠ يوليو ٢٠١٥  ·  17تعليقات  ·  مصدر: gorilla/sessions

لقد قمنا للتو بترقية هذه الحزمة ولم يتم تعيين ملفات تعريف الارتباط بشكل صحيح. إنه يقوم بتعيين أشياء مثل _ga = GA1.1.922831813.14264788986 بدلاً من بيانات ملفات تعريف الارتباط المشفرة base64. هل لديك أي فكرة عما يحدث أو متى حدث ذلك حتى نتمكن من العودة إلى إصدار يعمل؟ شكرا!

bug stale

التعليق الأكثر فائدة

لاحظ أن هذا يؤثر أيضًا على غالبية تطبيقات المتجر ، حيث يستخدمون جميعًا ملف تعريف الارتباط الآمن لحفظ المعرف في متجرهم الخلفي.

redistore لديه نصف التنفيذ الصحيح إذا قمت باستدعاء SetMaxAge يدويًا ولكن لا يتم تطبيق هذا بشكل مباشر على الحالة الافتراضية. يحدث فقط أن الافتراضي (30 يومًا) هو نفس ملف تعريف الارتباط الآمن.

من نظرة سريعة ، يبدو أن _ جميع_ المتاجر الأخرى قد تأثرت - لا يتم تطبيق إعداد MaxAge عبر بنية الخيارات على مثيلات ملف تعريف الارتباط الآمن التي تم إنشاؤها من CodecsFromPairs. لن يواجه معظم المستخدمين النهائيين هذا الخطأ لأنني أشك في أن معظم المستخدمين حددوا تواريخ انتهاء الصلاحية _ ما لم يتم تضمين ملف تعريف الارتباط الآمن ضمنيًا في HMAC.

FWIW: أعتقد أيضًا أن انتهاء صلاحية ملفات تعريف الارتباط "في المستقبل البعيد" لن تكون رائعة ما لم تكن لديك حاجة محددة جدًا لها.

ال 17 كومينتر

ملف تعريف الارتباط "_ga" غير مرتبط بالغوريلا / الجلسات - إنه أحد برامج Google Analytics
بسكويت.

إذا لم تقم الغوريلا / الجلسات بتعيين ملفات تعريف الارتباط (لم يكن هناك أي كسر
التغييرات) يمكنك نشر التعليمات البرمجية ذات الصلة وإخراج جزء ملفات تعريف الارتباط
من متصفحك؟ (المفتش> الموارد> ملفات تعريف الارتباط ضمن Chrome)

يوم الجمعة ، 10 تموز (يوليو) 2015 ، الساعة 7:12 صباحًا Marksalpeter [email protected]
كتب:

لقد قمنا للتو بترقية هذه الحزمة ولم يتم تعيين ملفات تعريف الارتباط بشكل صحيح. إنه
تعيين أشياء مثل _ga = GA1.1.922831813.14264788986 بدلاً من العادي
قاعدة بيانات ملف تعريف الارتباط المشفرة. أي فكرة عما يحدث أو عندما كسر هذا
يمكننا العودة إلى نسخة العمل؟ شكرا!

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/gorilla/sessions/issues/48.

مرحبا مات،

أنا أعمل أيضًا في المشروع مع Mark ويمكنني أن أقدم لك المزيد من التفاصيل. لذلك قمنا للتو بتحديث الحزمة لأن المشكلة الأصلية كانت تتعلق بملفات تعريف الارتباط جميعها تنتهي صلاحيتها بعد 30 يومًا حتى عندما قمنا بتعيين MaxAge على عدد كبير بالفعل. إليك رمز المصادقة الساري الآن والذي يسبب لنا مشاكل:

مقدار ثابت (
AUTH_SESSION_NAME = "جلسة المصادقة"
)

فار (
config = jconfig.LoadConfig (global.CONFIG () + "securecookie.json")
authKey = [] بايت (config.GetString ("authorization_key"))
encryptionKey = [] بايت (config.GetString ("encryption_key"))
الجلسة = الجلسات. NewCookieStore (authKey ، encryptionKey)
)

الحرف الأول () {

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

}

// يمنح هذا المعالج أذونات في النظام للأجهزة والمديرين
// إذا كان الطالب مفوضًا بالفعل ، فسيعرض معلوماته. إلى autherize غيف
// account ، يجب على العميل أولاً إلغاء المصادقة.
//
// بارامز
// المستعمل:
//
// ملاحظة: البيانات التي يتم إرجاعها من وظيفة المصادقة هذه مضمونة فقط لتكون دقيقة
// عندما يقوم المستخدم بالمصادقة لأول مرة. وإلا فإنه سيعرض البيانات المخزنة مؤقتًا في الجلسة الخاصة بهم
//
func Authenticate (response 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)
    }

}

}

وهذا ما نحصل عليه في السجلات بعد 30 يومًا:

ملف تعريف ارتباط الجهاز: جلسة المصادقة = _KaJDVq4lIdQgeHiHcnSMw1IEPDyg3-9XEIBBPxw == ؛ المسار = / ؛ تنتهي الصلاحية = الاثنين ، 15 مايو 2215 20:47:49 بالتوقيت العالمي المنسق ؛ الحد الأقصى للعمر = 6307200000

2015/07/10 15:56:04 /routers/api/Auth.go:70: ملف تعريف الارتباط الآمن: الطابع الزمني المنتهي

يبدو أن جميع ملفات تعريف الارتباط تنتهي صلاحيتها بعد 30 يومًا بغض النظر عما حددناه لـ MaxAge. أي مساعدة تكون ضخمة بالنسبة لنا. شكرا لك!

حسنًا ، لقد سخرت من الحد الأدنى من البرنامج التجريبي حيث قمت بتعيين MaxAge في المتجر بأكمله لمدة شهرين (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))
}

هذا يعطيني وقت انتهاء الصلاحية الذي أتوقعه:

Expiry time test

يؤدي ضبط ساعتي يدويًا إلى الأمام ~ 33 يومًا أيضًا إلى ظهور خطأ expired timestamp من securecookie - وهو خطأ.

مسح ملفات تعريف الارتباط في المتصفح ، وإعادة ضبط الساعة إلى الوراء () ثم فرض MaxAge على *securecookie.SecureCookie خلال ما يلي:

    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)
        }
    }

لا يزال هذا يعطيني ملف تعريف ارتباط للمتصفح مع انتهاء صلاحية +2 أشهر في المستقبل لأن الحقل maxAge لكل برنامج ترميز لا يؤثر على ما يراه المتصفح عندما نكتب http.Cookie . ومع ذلك ، فإن ضبط ساعتي +33 يومًا في المستقبل لا يولد خطأ الطابع الزمني منتهي الصلاحية.

لذلك قمت ببعض الحفر:

  • تم إنشاء الخطأ "securecookie: expired timestamp" من https://github.com/gorilla/securecookie/blob/master/securecookie.go#L244 -L246
  • يعيّن هذا السطر MaxAge عند إنشاء CookieStore: https://github.com/gorilla/sessions/blob/master/store.go#L54 -L56
  • من خلال استدعاء CodecsFromPairs قبل تطبيق الخيارات ، يتم إصلاح s.MaxAge داخل كل *securecookie.SecureCookie (كجزء من شريحة الترميز) إلى الإعداد الافتراضي لملف تعريف الارتباط الآمن: 86400 * 30 .
  • إذا كان لدينا نطاق فوق sessions.CookieStore.Codecs (وفقًا للمقتطف أعلاه) وقمنا بتعيين MaxAge في كل مثيل ملف تعريف ارتباط آمن ، فإننا نتحايل على هذا.

TL ؛ DR : السبب الأساسي هو أن http.Cookie المكتوب على المتصفح يحصل على الطابع الزمني الذي حددناه في خياراتنا ، لكن HMAC لمثيل ملف تعريف الارتباط الأمني ​​الأساسي هو سلسلة من التاريخ | القيمة | mac - حيث يكون التاريخ _default_ MaxAge الذي لا تعمل خياراتنا على إصلاحه. فشل التحقق من صحة HMAC بعد ذلك بمجرد وصولنا إلى> 30 يومًا.

سيكون الإصلاح لـ sessions.NewCookieStore للنطاق عبر برامج الترميز التي ينشئها ويطبقها. MaxAge لكل مثيل *securecookie.SecureCookie للسماح له بتصحيح عدم التطابق بين انتهاء صلاحية ملف تعريف الارتباط والتحقق من صحة الطابع الزمني لـ HMAC.

cc / kisielk للتحقق من صحة النتائج التي توصلت إليها قبل دفع الإصلاح.

ملاحظة: بخلاف ذلك ، من الأفضل فتح تجمع قاعدة بيانات واحد في برنامجك ، سواء كان ذلك عبر عام أو بتمرير مؤشر بشكل صريح. فتح وإغلاق التجمع لكل طلب نتيجة أداء. *sql.DB آمن للوصول المتزامن.

لاحظ أن هذا يؤثر أيضًا على غالبية تطبيقات المتجر ، حيث يستخدمون جميعًا ملف تعريف الارتباط الآمن لحفظ المعرف في متجرهم الخلفي.

redistore لديه نصف التنفيذ الصحيح إذا قمت باستدعاء SetMaxAge يدويًا ولكن لا يتم تطبيق هذا بشكل مباشر على الحالة الافتراضية. يحدث فقط أن الافتراضي (30 يومًا) هو نفس ملف تعريف الارتباط الآمن.

من نظرة سريعة ، يبدو أن _ جميع_ المتاجر الأخرى قد تأثرت - لا يتم تطبيق إعداد MaxAge عبر بنية الخيارات على مثيلات ملف تعريف الارتباط الآمن التي تم إنشاؤها من CodecsFromPairs. لن يواجه معظم المستخدمين النهائيين هذا الخطأ لأنني أشك في أن معظم المستخدمين حددوا تواريخ انتهاء الصلاحية _ ما لم يتم تضمين ملف تعريف الارتباط الآمن ضمنيًا في HMAC.

FWIW: أعتقد أيضًا أن انتهاء صلاحية ملفات تعريف الارتباط "في المستقبل البعيد" لن تكون رائعة ما لم تكن لديك حاجة محددة جدًا لها.

أود أيضًا أن أشير إلى أن الطابع الزمني الحالي غير مشفر تمامًا في التطبيق الحالي. يمكنني ، نظريًا ، فك تشفير ملف تعريف الارتباط base64 ، وتغيير الطابع الزمني إلى اليوم الحالي ، وترميز ملف تعريف الارتباط base64 ، وبعد ذلك لن تكون خاصية MaxAge مهمة على الإطلاق ، حتى لو قمت بإصلاح الخيارات. مشكلة MaxAge.

نعم ، كان ملف تعريف الارتباط "المستقبل البعيد" مجرد اختبار ، فلدينا MaxAge مضبوطًا على 0 على خادم الإنتاج لدينا الآن. لقد وجدنا المشكلة خلال عطلة نهاية الأسبوع وكتبنا إصلاحًا مشابهًا ، ولكنه أقل إيجازًا من إصلاحك.

شكرا للنظر في المشكلة!

wbaron - لا مشاكل. سنصلحه في حزمة المنبع قريبًا و
سأقوم باختبار اتصالك مرة واحدة حتى لا تضطر إلى الاحتفاظ بالشوكة الخاصة بك (إذا قمت بذلك
لا تريد).

marksalpeter - هل يمكنك الإشارة إلى أين؟ Securecookie MACs
الاسم | التاريخ | القيمة قبل ترميز base64 لتمثيل سلسلة. إذا
تقوم بفك الشفرة من جانب العميل ، ولا يمكنك تعديل الطابع الزمني هناك (إنه
MAC'ed - لا يوجد شيء يمكنك تعديله بالفعل) وإذا حاولت ذلك ، فإن ملف
يجب أن يفشل ملف تعريف الارتباط في التحقق من صحة عند فك (طلب) لأن MAC ستفشل
لفك التشفير بشكل صحيح مقابل مفتاح التجزئة / المصادقة. المرجع:
https://github.com/gorilla/securecookie/blob/master/securecookie.go#L185 -L191

في الثلاثاء ، 14 يوليو 2015 الساعة 10:40 مساءً كتب wbaron [email protected] :

نعم ، كان ملف تعريف الارتباط "المستقبل البعيد" مجرد اختبار ، فلدينا مجموعة MaxAge
0 على خادم الإنتاج لدينا الآن. وجدنا المشكلة خلال عطلة نهاية الأسبوع و
كتب إصلاحًا مشابهًا لإصلاحك ، بقليل من الإيجاز.

شكرا للنظر في المشكلة!

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/gorilla/sessions/issues/48#issuecomment -121257995.

elithrar خطأي. عندما أقوم بفك تشفير ملفات تعريف الارتباط ، أحصل على [الطابع الزمني] | [معلومات MAC] افترضت للتو أن الطابع الزمني قبل المعلومات القصوى هو ما كنت تستخدمه.

elithrar ما تقترحه يبدو جيدًا بالنسبة لي. عار أنه يجب تطبيقه على كل متجر على حدة: /

@ kisielk - عار بالتأكيد. كنت أرغب في تجنب لمس الطرف الثالث
المتاجر ولكن لم تكن هناك طريقة نظيفة لربط متجر طرف ثالث بشكل فعال
Options.MaxAge الحقول باستخدام طريقة s.MaxAge في ملف تعريف الارتباط الآمن.

أفكر في تقديم دالة func CodecMaxAge(codecs []Codec, age int) []Codec في ملف تعريف ارتباط آمن (الجانب السلبي: لا يمكن أن يكون طريقة على
واجهة + تضيف إلى واجهة برمجة التطبيقات العامة) التي تقوم بهذا النوع داخليًا
التأكيد + المكالمات s.MaxAge (العمر) على كل برنامج ترميز. هذا يبقي زائدة عن الحاجة (loop
فوق الشريحة ، اكتب التأكيد على نوع ملف تعريف الارتباط) كود خارج متاجر الطرف الثالث
حيث سيحتاجون فقط إلى استدعاء securecookie.CodecMaxAge(mystore.Codecs, mystore.opts.MaxAge) في وظيفتهم NewXXXXStore لتعيين
حقل s.maxAge الأساسي.

منفتح على أفكار أفضل ولكن يبدو أن هذا هو الأبسط.

يوم الجمعة 17 يوليو 2015 الساعة 8:03 صباحًا Kamil Kisiel [email protected]
كتب:

elithrar https://github.com/elithrar يبدو ما تقترحه جيدًا
أنا. عار أنه يجب تطبيقه على كل متجر على حدة: /

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/gorilla/sessions/issues/48#issuecomment -122133977.

نعم أعتقد أنه بخير. سأرسل بعض العلاقات العامة إلى المتاجر الأخرى لاستخدامها بمجرد وصولك للتغيير هنا.

لأغراض التتبع:

  • [x] [غوريلا / جلسات] (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) - بولت
  • [] [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
  • [] [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb على 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 على 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

سأتعقب هذه بمجرد دمج العلاقات العامة.

تم وضع علامة على هذه المشكلة تلقائيًا على أنها قديمة لأنها لم تشهد تحديثًا مؤخرًا. سيتم إغلاقه تلقائيًا في غضون أيام قليلة.

بالنظر إلى هذه المشكلة بعد تشغيلها من حزمة أخرى ، لا يبدو أنه يجب إغلاقها ... لا تزال قائمة التحقق من elithrar بحاجة إلى 10 فحوصات أخرى ، ما لم تكن هذه المعلومات قديمة.

يجب أن يكون دقيقًا: ولكن لا تتم صيانة جميع المتاجر بشكل نشط أو تقديم بيان عام.

تم وضع علامة على هذه المشكلة تلقائيًا على أنها قديمة لأنها لم تشهد تحديثًا مؤخرًا. سيتم إغلاقه تلقائيًا في غضون أيام قليلة.

تم وضع علامة على هذه المشكلة تلقائيًا على أنها قديمة لأنها لم تشهد تحديثًا مؤخرًا. سيتم إغلاقه تلقائيًا في غضون أيام قليلة.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات