تجزئة السر + الحمولة لـ SSO

أنا أحاول اتباع دليل SSO الرسمي. أستخدم Golang على خادمي، وأحاول مطابقة تجزئة HMAC-SHA256 لـ payload + secret مع sig، لكنني أحصل على قيم مختلفة. كيف تقومون بعملية التجزئة؟ هل تقومون بتحليل الـ payload إلى المحتوى الخام غير الموقّع ثم إعادة تجزئته؟

كيف يبدو كودك؟

هل قمت بتشفير الحمولة باستخدام Base64؟

وهل الترتيب الصحيح للمعاملات؟ تختلف لغات البرمجة والمكتبات في ترتيب المعاملات (المفتاح، الرسالة) أو (الرسالة، المفتاح). هذا ما يخدعني في كل مرة.

بعد تحليل payload، يبدو أنه مشفر بـ base64 افتراضيًا، لكن تجزئة SHA256 للـ payload المشفر بـ base64 غير صحيحة. أنا أستخدم السرية والرابط من المنشور الأصلي.

الكود التالي يعطيني المخرجات التالية:

 payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=

sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = KCiqKYmXIrNaLxkdNO+bPOaV4Obu7EfetG1YjXDHy1Y=

كودي:

testURL := "http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56"	
	ssoSecret := "d836444a9e4084d5b224a60c208dce14"

	// جلب الـ payload والـ sig من استعلام الرابط
	u, err := url.Parse(testURL)
	if err != nil {
		log.Fatal(err)
	}

	q := u.Query()
	payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "=[]")
	sig := strings.Trim(fmt.Sprint(q["sig"]), "[]")
	
	fmt.Printf("payloadURL = %s\n", payloadURL)
	fmt.Printf("sig = %s\n", sig)

	// الحصول على الـ payload الخام من النسخة المشفرة بـ base64
	payloadRaw, err := base64.StdEncoding.DecodeString(payloadURL)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("payloadRaw = %s\n", payloadRaw)
	
	key := []byte(ssoSecret)
	message := []byte(payloadURL)
	hash := hmac.New(sha256.New, key)
	hash.Write(message)
	payload256 := base64.StdEncoding.EncodeToString(hash.Sum(nil))
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("payload256 = %s\n", payload256)

	// الـ sig مشفر بصيغة سداسية عشرية، لذا قم بترميز الـ payload الممزوج بصيغة سداسية عشرية للمقارنة.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// قارن بين تجزئة الـ payload المشفرة بصيغة سداسية عشرية والـ sig المشفر بصيغة سداسية عشرية
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

تحديث: أصلحت المشكلة بعد ترميز تجزئة HMAC-SHA256 الناتجة بصيغة سداسية عشرية (الـ signature مشفر أيضًا بصيغة سداسية عشرية. انظر أيضًا هذا المنشور الذي يشير إلى أن الأمثلة في دليل SSO غير صحيحة. لذا قمت بتعديل هذا الكود:

key := []byte(ssoSecret)
message := []byte(payloadURL)
hash := hmac.New(sha256.New, key)
hash.Write(message)
payload256 := hex.EncodeToString(hash.Sum(nil))
if err != nil {
	log.Fatal(err)
}

من أين يأتي payload256؟

عذرًا، قمت بتحديث المنشور الأصلي (OP) بأكواد أكثر نظافة.

ما الذي يفعله %0A هناك مباشرة قبل &sig؟ إنه سطر جديد مشفر كـ URL… وهذا هو السبب في وجود سطر فارغ في مخرجات التصحيح الخاصة بك بعد طباعة payloadURL، فهو لا يزال مرفقًا في النهاية.

تصويب ممتاز! قمت بإصلاح ذلك هنا بإضافة حرف السطر الجديد إلى معلمات .Trim():

payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "[]\n")

لذا أصبح مخرجي الآن:

payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=
sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = HOFJT5RIS29qCSvpsVzMHNr7H4Rgo4OPuw4Ig8Q5BHE=

ينبغي عليك التحقق من مصدر السطر الجديد الفعلي وتجنب إضافته.

أيضًا، هل يجب أن يحتوي الحمولة على أزواج اسم=قيمة أكثر من مجرد nonce؟

هذه مجرد أمثلة من دليل SSO الخاص بـ Discourse، لذا لا يمكنني تحديد مصدر السطر الجديد. يبدو أن الدليل غير صحيح (وفقًا لـ هذا المنشور)، ويبدو أن هناك خطأ في النسخ/اللصق في المثال.

ربما هناك قدر كبير جدًا من النسخ واللصق من إصدارات مختلفة.

ولكن بالنظر إلى منشورك أعلاه مباشرةً، فإن payloadURL غير مشفر كـ URL، و payload256 غير مشفر بصيغة سداسية عشرية بل مشفر بصيغة Base64.

ربما يمكنك إعادة نشر الكود الحالي ومخرجاتك الحالية.