บทความ

คุณคงเคยเจอสถานการณ์นี้: สคริปต์ทำงาน เข้าสู่ระบบเว็บไซต์ ใส่สินค้าลงตะกร้า แล้วอยู่ ๆ ก็มีการเปลี่ยน IP และเซิร์ฟเวอร์ตอบกลับเหมือนกับว่าคุณเพิ่งมาเยือนครั้งแรก ผู้ใช้ถูกออกจากระบบ ตะกร้าว่างเปล่า โทเค็นใช้งานไม่ได้ น่าหงุดหงิดใช่ไหม? ใช่เลย แต่ปัญหานี้มีวิธีแก้ไขเชิงวิศวกรรมที่ชัดเจน และในคู่มือนี้เราจะพูดถึงมันตั้งแต่ต้นจนจบ

บทนำ: ทำไมหลังเปลี่ยน IP ถึงโดนออกจากระบบและตะกร้าถึงว่างเปล่า

พูดกันตรง ๆ ว่าเมื่อเซสชันหลุดหลังจากการเปลี่ยน IP สิ่งแรกที่อยากทำคือโทษการเปลี่ยนที่อยู่เสียเอง ก็แบบว่า IP เปลี่ยนเซิร์ฟเวอร์เห็นแล้วก็รีเซ็ตทุกอย่าง บางครั้งก็จริง แต่บ่อยครั้งที่ปัญหาอยู่ที่โค้ดของคุณ ไม่ใช่ที่ IP ตัวมันเอง โค้ดสับสนสถานะของเซสชันต่าง ๆ ทำคุกกี้หาย และส่งโทเค็นเก่าจากที่อยู่ใหม่ เราจะเรียนรู้วิธีทำให้สิ่งเหล่านี้ไม่เกิดขึ้น

ผู้อ่านจะได้อะไรเมื่ออ่านจบ

เมื่ออ่านคู่มือนี้จบ คุณจะทำสิ่งต่อไปนี้ได้ ประการแรก เข้าใจว่าสิ่งใดผูกกับ IP จริง ๆ ฝั่งเซิร์ฟเวอร์ และสิ่งใดเป็นเพียงความเชื่อผิด ๆ ประการที่สอง วางกฎการจับคู่ที่เคร่งครัด: หนึ่งเซสชันเชิงตรรกะเท่ากับหนึ่งชุดคุกกี้เท่ากับหนึ่ง IP ประการที่สาม เขียนโค้ดที่ใช้งานได้จริงบน Python และ Node.js ซึ่งแยกสถานะระหว่างพร็อกซีต่าง ๆ และไม่ปนกัน ประการที่สี่ เก็บสถานะระหว่างการรันโปรแกรมและรู้ว่าเมื่อไหร่ควรทิ้งมันทิ้งไป

คู่มือนี้เหมาะสำหรับใคร

คู่มือนี้เหมาะสำหรับระดับกลาง คุณเขียนโค้ด Python หรือ JavaScript ได้แล้ว เข้าใจว่า HTTP request คืออะไร และพอรู้ว่าพร็อกซีมีไว้ทำไม เราจะไม่พูดถึงว่าจะเลือกการหมุนเวียนแบบไหน เพราะมีบทความแยกต่างหาก ที่นี่เรามองว่าการเปลี่ยน IP เกิดขึ้นตามกฎของคุณอยู่แล้ว และเราจะแก้ปัญหาเพียงข้อเดียว: จะไม่ให้สถานะหายไประหว่างการเปลี่ยนนี้ได้อย่างไร

สิ่งที่ควรรู้ก่อนเริ่ม

ควรเข้าใจพื้นฐานก่อน คุกกี้คือข้อมูลชิ้นเล็ก ๆ ที่เซิร์ฟเวอร์ขอให้เบราว์เซอร์หรือไคลเอนต์จดจำและส่งกลับมาในทุกคำขอ เซสชันคือวิธีที่เซิร์ฟเวอร์จดจำคุณระหว่างคำขอต่าง ๆ โทเค็นคือสายอักขระที่ยืนยันตัวตนหรือสิทธิ์ในการดำเนินการ หากคำเหล่านี้ยังคลุมเครือ ไม่ต้องกังวล ในส่วนแนวคิดพื้นฐานเราจะอธิบายแต่ละคำแบบง่าย ๆ

ใช้เวลานานเท่าไร

การอ่านและทำความเข้าใจทฤษฎีใช้เวลาประมาณสี่สิบนาที การดูโค้ดและรันบนภาษาที่คุณใช้เพิ่มอีกหนึ่งถึงหนึ่งชั่วโมงครึ่ง การเข้าใจอย่างถ่องแท้พร้อมทดลองกับโจทย์จริงใช้เวลาสองถึงสามชั่วโมง อย่ารีบ มันดีกว่าที่จะค่อย ๆ เข้าใจหลักการ แทนที่จะรีบคัดลอกโค้ดแล้วเจอปัญหาแปลก ๆ ทีหลัง

การเตรียมตัวเบื้องต้น: เครื่องมือและสภาพแวดล้อม

ก่อนเขียนโค้ด เรามาจัดสภาพแวดล้อมการทำงานให้เรียบร้อยก่อน ใช้เวลาไม่นาน แต่จะช่วยประหยัดเวลาการดีบั๊กเป็นชั่วโมงในภายหลัง

เครื่องมือที่จำเป็น

  • Python เวอร์ชัน 3.10 ขึ้นไป - หากคุณใช้ Python ในปี 2026 เวอร์ชันที่ใช้งานจริงคือ 3.12 และ 3.13 แต่ทุกอย่างในบทความนี้ใช้งานได้ตั้งแต่ 3.10
  • Node.js เวอร์ชัน 20 LTS ขึ้นไป - หากคุณใช้ JavaScript เวอร์ชัน 22 LTS ก็ได้
  • พร็อกซีแบบหมุนเวียน IP - คุณควรมีสิทธิ์เข้าถึงกลุ่มที่อยู่แล้ว รูปแบบการเชื่อมต่อโดยทั่วไปคือ: โปรโตคอล โฮสต์ พอร์ต ชื่อผู้ใช้ และรหัสผ่าน
  • โปรแกรมแก้ไขโค้ด - อันไหนก็ได้ เช่น โปรแกรมแก้ไขฟรีที่ไฮไลต์ไวยากรณ์
  • เทอร์มินัลหรือพร้อมต์คำสั่ง - ใช้สำหรับติดตั้งไลบรารีและรันสคริปต์

ความต้องการของระบบ

ความต้องการไม่สูง คอมพิวเตอร์สมัยใหม่ทุกเครื่องรับได้ แรม 4 กิกะไบต์ก็เพียงพอ แต่ถ้าวางแผนจะรันหลายเซสชันพร้อมกัน แนะนำ 8 กิกะไบต์ขึ้นไป สิ่งสำคัญกว่าคือการเชื่อมต่ออินเทอร์เน็ตที่เสถียร เพราะถ้าการเชื่อมต่อขาด คุกกี้ อาจไม่ถูกบันทึกอย่างถูกต้อง

สิ่งที่ต้องติดตั้ง

สำหรับ Python ให้ติดตั้งไลบรารีสองตัว เปิดเทอร์มินัลแล้วรันคำสั่งติดตั้งแพ็กเกจ requests และแพ็กเกจสำหรับทำงานกับพร็อกซี เขียนแบบนี้: อันดับแรกคือคำสั่งติดตั้งของตัวจัดการแพ็กเกจ จากนั้นตามด้วยชื่อ requests สำหรับการซีเรียลไลซ์สถานะ ใช้โมดูลมาตรฐานได้ ไม่ต้องติดตั้งแยก

สำหรับ Node.js ให้ติดตั้งสามแพ็กเกจ: axios สำหรับคำขอ, tough-cookie สำหรับจัดการที่เก็บคุกกี้ และ https-proxy-agent สำหรับเชื่อมต่อผ่านพร็อกซี ทั้งสามติดตั้งด้วยคำสั่งติดตั้งแพ็กเกจคำสั่งเดียวในโปรเจกต์ของคุณ

เคล็ดลับ: สร้างโฟลเดอร์เสมือนแยกสำหรับโปรเจกต์ ใน Python คือ virtual environment ใน Node.js คือไดเรกทอรีแยกที่มีไฟล์อธิบาย dependencies วิธีนี้จะได้ไม่ปนไลบรารีของโปรเจกต์ต่าง ๆ และหลีกเลี่ยงปัญหาเวอร์ชันขัดแย้ง

การสร้างข้อมูลสำรอง

หากคุณบันทึกคุกกี้เป็นไฟล์หรือฐานข้อมูลอยู่แล้ว ควรสำเนาข้อมูลก่อนทดลอง เพราะเราจะเปลี่ยนตรรกะการซีเรียลไลซ์ และอาจมีความเสี่ยงทำให้ข้อมูลเดิมเสียหาย แค่คัดลอกโฟลเดอร์ที่มีสถานะบันทึกไว้ไปไว้ที่ที่ทำเครื่องหมาย backup

การตรวจสอบ: หลังติดตั้งให้แน่ใจว่าทุกอย่างทำงาน รันคำสั่งตรวจสอบเวอร์ชัน Python หรือ Node.js ในเทอร์มินัลสั้น ๆ คุณควรเห็นเลขเวอร์ชันโดยไม่มีข้อผิดพลาด จากนั้นลอง import ไลบรารีที่ติดตั้งในโหมดอินเทอร์แอกทีฟ หาก import ผ่านเงียบ ๆ แสดงว่าพร้อมแล้ว

แนวคิดพื้นฐาน: อะไรผูกกับ IP และอะไรคือความเชื่อผิด ๆ

นี่คือส่วนทฤษฎีที่สำคัญที่สุด ถ้าคุณยังไม่เข้าใจว่าอะไรเกี่ยวข้องกับ IP จริง ๆ คุณจะรักษาโรคผิดตัว เราไปดูข้อมูลแต่ละประเภทกันตามลำดับ

คุกกี้เซสชัน

คุกกี้เซสชันคือเมื่อเซิร์ฟเวอร์ออก ID เซสชันในรูปแบบคุกกี้ให้คุณ และเก็บสถานะไว้ที่ฝั่งตัวเอง เช่น คุกกี้ชื่อ sessionid ที่มีสตริงสุ่มยาว ๆ อยู่ข้างใน เซิร์ฟเวอร์ใช้สตริงนี้เพื่อหาข้อมูลของคุณในหน่วยความจำ กลไกนี้ผูกกับ IP หรือไม่? โดยตัวมันเองแล้วไม่ผูก คุกกี้ทำงานโดยไม่ขึ้นกับที่อยู่ แต่หลายบริการเพิ่มการตรวจสอบพิเศษ: พวกเขาจำว่าเซสชันถูกสร้างจาก IP ใด และหากคำขอที่มีคุกกี้เดียวกันมาจากที่อยู่อื่น ก็ถือว่าน่าสงสัย นี่คือจุดที่ทำให้ถูกออกจากระบบ

โทเค็น CSRF

โทเค็น CSRF คือการป้องกันการปลอมแปลงคำขอ เซิร์ฟเวอร์ออกโทเค็นให้ แล้วคุณต้องส่งกลับมาเมื่อส่งฟอร์มหรือทำรายการสำคัญ โทเค็นนี้แทบไม่ผูกกับ IP เลย มันผูกกับเซสชัน ไม่ใช่ที่อยู่ ปัญหาที่เกิดขึ้นมีสาเหตุอื่น: หากคุณทำคุกกี้เซสชันหาย โทเค็น CSRF ก็จะใช้ไม่ได้เช่นกัน เพราะเซิร์ฟเวอร์ไม่สามารถจับคู่มันกับเซสชันของคุณได้ นั่นหมายความว่าปัญหานี้เป็นเรื่องรอง - เป็นผลพวงจากการทำคุกกี้หาย

JWT

JWT คือโทเค็นที่นำข้อมูลติดตัวไปด้วยและได้รับการเซ็นชื่อโดยเซิร์ฟเวอร์ ไคลเอนต์เก็บไว้และส่งในส่วนหัวของทุกคำขอ JWT แบบคลาสสิกไม่ผูกกับ IP เลย มันพอเพียงในตัวเอง: เซิร์ฟเวอร์ตรวจสอบลายเซ็นและวันหมดอายุ และไม่สนใจที่อยู่ แต่ก็มีการใช้งานบางรูปแบบที่เซิร์ฟเวอร์เก็บการผูกโทเค็นกับ IP ไว้ฝั่งตัวเอง หรือใส่ที่อยู่เข้าไปในโทเค็น ในกรณีเช่นนี้การเปลี่ยน IP จะทำให้การตรวจสอบล้มเหลว นี่ไม่ใช่คุณสมบัติของ JWT แต่เป็นการตัดสินใจของบริการนั้น ๆ

เซสชันฝั่งเซิร์ฟเวอร์

เซสชันฝั่งเซิร์ฟเวอร์คือชื่อรวมสำหรับสถานะที่เซิร์ฟเวอร์เก็บไว้และเชื่อมโยงกับ ID ของคุณ ตะกร้าสินค้า ประวัติการเข้าชม สถานะการล็อกอิน มักอยู่ในเซสชันฝั่งเซิร์ฟเวอร์ การผูกกับ IP ในที่นี้ขึ้นอยู่กับการตั้งค่าของบริการ บางบริการเพื่อความปลอดภัยผูกเซสชันกับ IP แรกอย่างเข้มงวด บางบริการยืดหยุ่นต่อการเปลี่ยนที่อยู่ โดยปกติคุณไม่รู้ล่วงหน้า จึงควรเขียนโค้ดเหมือนมีการผูกไว้ นั่นคือกลยุทธ์ที่ปลอดภัย

ตะกร้าสินค้า

ตะกร้าสินค้าเป็นกรณีหนึ่งของเซสชันฝั่งเซิร์ฟเวอร์หรือคุกกี้ ในร้านค้าทั่วไป ตะกร้าจะถูกเก็บในคุกกี้ที่ฝั่งไคลเอนต์ ในร้านค้าซับซ้อน จะเก็บอยู่บนเซิร์ฟเวอร์ โดยผูกกับเซสชัน หากตะกร้าว่างเปล่าหลังเปลี่ยน IP แสดงว่ามันถูกผูกกับเซสชันฝั่งเซิร์ฟเวอร์ที่ตรวจสอบที่อยู่ วิธีแก้ก็เหมือนเดิม: อย่าเปลี่ยน IP ภายในเซสชันเชิงตรรกะเดียว หรือเก็บคุกกี้ทั้งหมดอย่างระมัดระวัง

สรุป: IP เกี่ยวข้องตรงไหนจริง ๆ

มาสรุปภาพรวมกัน กลไก HTTP ของคุกกี้, CSRF, JWT ไม่ผูกกับ IP การผูกเกิดขึ้นเป็นการตรวจสอบเพิ่มเติมฝั่งบริการ และคุณไม่สามารถควบคุมมันได้ สิ่งเดียวที่คุณควบคุมได้คือความสอดคล้องระหว่างเซสชัน ชุดคุกกี้ และ IP ฝั่งคุณ ดังนั้นจึงเกิดกฎหลักของคู่มือนี้

การตรวจสอบ: ลองทดสอบความเข้าใจของคุณ หากเปลี่ยน IP แล้วเซสชันหลุด แต่เมื่อกลับไปที่ IP เดิมทุกอย่างกลับมาเหมือนเดิม แสดงว่าเซิร์ฟเวอร์ตรวจสอบที่อยู่อย่างเข้มงวด หากไม่กลับมาแม้จะอยู่ที่ IP เดิม แสดงว่าคุณทำคุกกี้หายในโค้ด นี่คือสองโรคที่ต่างกันและการรักษาที่ต่างกัน

ขั้นตอนที่ 1: กำหนดกฎการจับคู่

เป้าหมายของขั้นตอนนี้: ยึดหลักการสำคัญและเข้าใจวิธีแสดงออกมาในโครงสร้างโค้ด

กฎฟังดูง่าย: หนึ่งเซสชันเชิงตรรกะเท่ากับหนึ่งชุดคุกกี้เท่ากับหนึ่ง IP มาดูกันว่าหมายความว่าอย่างไรในทางปฏิบัติ

  1. เซสชันเชิงตรรกะคือห่วงโซ่ของคำขอที่แทนงานต่อเนื่องหนึ่งงาน: เข้ามา ล็อกอิน ทำอะไรบางอย่าง ออกไป ทั้งหมดนี้คือหนึ่งเซสชันเชิงตรรกะ
  2. หนึ่งชุดคุกกี้คือที่เก็บคุกกี้แยกต่างหากที่เป็นของเซสชันเชิงตรรกะนี้เท่านั้น ไม่ใช่ของใครอื่น
  3. หนึ่ง IP - ภายในเซสชันเชิงตรรกะเดียว ที่อยู่จะไม่เปลี่ยน หากมีการหมุนเวียนเกิดขึ้นจริง เซสชันเชิงตรรกะนั้นถือว่าจบลง

จะแสดงสิ่งนี้ในโค้ดได้อย่างไร? ง่ายมาก: สร้างออบเจกต์คอนเทนเนอร์ที่ภายในเก็บทั้งที่เก็บคุกกี้และการตั้งค่าพร็อกซี ตราบใดที่ออบเจกต์นี้ยังมีชีวิต เซสชันเชิงตรรกะก็ยังมีชีวิต เมื่อถึงเวลาเปลี่ยน IP เราจะสร้างคอนเทนเนอร์ใหม่ หรือหากบริการยอมรับการเปลี่ยนที่อยู่ ก็ย้ายคุกกี้ไปยังคอนเทนเนอร์ใหม่กับ IP ใหม่อย่างระมัดระวัง

⚠️ ข้อควรระวัง: ข้อผิดพลาดทางสถาปัตยกรรมที่พบบ่อยที่สุดคือการเก็บคุกกี้ชุดเดียวแล้วใส่พร็อกซีต่าง ๆ เข้าไป นี่จะทำให้ทุกอย่างพังแน่นอน เซสชันเชิงตรรกะต่าง ๆ จะเริ่มเขียนทับคุกกี้ของกันและกัน และเซิร์ฟเวอร์ได้รับข้อมูลที่ขัดแย้งกัน อย่าทำแบบนี้เด็ดขาด

เคล็ดลับ: คิดว่าเซสชันเชิงตรรกะเป็นเหมือนบุคคล คนหนึ่งมีเอกสารชุดเดียว (คุกกี้) และบ้านหนึ่งหลัง (IP) เป็นไปไม่ได้ที่คนสองคนจะใช้เอกสารชุดเดียวกัน และเป็นไปไม่ได้ที่คนคนหนึ่งจะอยู่สองบ้านพร้อมกัน อุปมานี้จะช่วยป้องกันข้อผิดพลาดส่วนใหญ่ได้

การตรวจสอบ: วาดโครงสร้างที่คุณวางแผนไว้บนกระดาษ คุณควรได้บล็อกอิสระหลายบล็อก แต่ละบล็อกมีที่เก็บคุกกี้และพร็อกซีของตัวเอง ไม่มีข้อมูลร่วมกันระหว่างบล็อก ถ้าได้แบบนี้แสดงว่าคุณเข้าใจกฎแล้ว

ขั้นตอนที่ 2: ปฏิบัติจริงกับ Python - Session สำหรับแต่ละพร็อกซี

เป้าหมายของขั้นตอนนี้: เขียนโค้ดที่ใช้งานได้จริง โดยแต่ละเซสชันเชิงตรรกะมีออบเจกต์ requests.Session ของตัวเอง มี CookieJar ของตัวเอง และพร็อกซีของตัวเอง แยกจากกันโดยสิ้นเชิง

ในไลบรารี requests มีออบเจกต์ Session ซึ่งตัวมันเองเป็นคอนเทนเนอร์: ภายในเก็บที่เก็บคุกกี้และสามารถใช้การตั้งค่ากับทุกคำขอได้ นี่คือพื้นฐานที่เหมาะสำหรับเซสชันเชิงตรรกะของเรา

โครงสร้างพื้นฐาน

  1. สร้างฟังก์ชันที่รับข้อมูลของพร็อกซีหนึ่งตัวและคืนค่าออบเจกต์ Session ที่พร้อมใช้งาน
  2. ภายในฟังก์ชันสร้างออบเจกต์ Session ใหม่
  3. กำหนดค่าพร็อกซีให้ออบเจกต์ - พจนานุกรมที่มีที่อยู่พร็อกซีสำหรับโปรโตคอล http และ https
  4. คืนค่าออบเจกต์ ตอนนี้คุณมีคอนเทนเนอร์ที่แยกเป็นอิสระแล้ว

โค้ดมีลักษณะแบบนี้ ทีละบรรทัด: import requests กำหนดฟังก์ชัน make_session ที่รับสตริง proxy_url ภายในเขียน s = requests.Session() จากนั้น s.proxies = พจนานุกรมที่คีย์ http ชี้ไปที่ proxy_url และคีย์ https ชี้ไปที่ proxy_url สุดท้าย return s แค่นี้ฟังก์ชันก็เสร็จ

ทำไมสิ่งนี้ถึงแยกสถานะได้

การเรียก make_session แต่ละครั้งจะสร้างออบเจกต์ใหม่ทั้งหมด ออบเจกต์ใหม่มีที่เก็บคุกกี้ภายในของตัวเองที่เรียกว่า cookiejar คุกกี้ที่ได้จากเซสชันหนึ่งไม่สามารถไปอยู่อีกเซสชันหนึ่งได้จริง ๆ เพราะมันเป็นคนละออบเจกต์ในหน่วยความจำ นี่คือสิ่งที่เราต้องการ

การใช้งานเซสชัน

  1. รับออบเจกต์เซสชันโดยเรียกฟังก์ชันพร้อมพร็อกซีที่ต้องการ
  2. ส่งคำขอผ่านเมธอดของออบเจกต์นี้: s.get หรือ s.post
  3. คุกกี้ที่เซิร์ฟเวอร์ส่งมาในส่วนหัว Set-Cookie จะถูกบันทึกในออบเจกต์โดยอัตโนมัติ
  4. ในคำขอถัดไปผ่านออบเจกต์เดียวกัน คุกกี้เหล่านี้จะถูกส่งกลับโดยอัตโนมัติ

เคล็ดลับ: อย่าสร้าง Session ใหม่สำหรับทุกคำขอภายในเซสชันเชิงตรรกะเดียว เพราะคุกกี้จะไม่สะสม ให้สร้างออบเจกต์หนึ่งครั้งต่อเซสชันเชิงตรรกะทั้งหมดแล้วใช้มันสำหรับทุกคำขอของเซสชันนั้น

การแยกระหว่างเธรด

หากคุณทำงานแบบหลายเธรด แต่ละเธรดต้องมีออบเจกต์ Session ของตัวเอง ออบเจกต์ Session ไม่ปลอดภัยต่อเธรด นั่นหมายความว่าหากสองเธรดเขียนคุกกี้ลงในออบเจกต์เดียวกันพร้อมกัน ข้อมูลอาจเสียหาย

  1. ใช้กลไกข้อมูลเฉพาะเธรด ใน Python คือออบเจกต์ threading.local
  2. เมื่อเริ่มแต่ละเธรด ให้สร้างเซสชันแยกสำหรับเธรดนั้นและเก็บไว้ในที่เก็บเฉพาะเธรด
  3. ภายในเธรดให้เข้าถึงเฉพาะเซสชันของตัวเอง อย่าแตะของคนอื่น

ในทางปฏิบัติมีลักษณะแบบนี้: สร้างออบเจกต์ global local = threading.local() ตอนเริ่มงานของเธรด ให้ตรวจสอบว่า local มี attribute session หรือไม่ ถ้าไม่มีก็สร้างด้วยการเรียก make_session พร้อมพร็อกซีที่กำหนดให้เธรดนี้ จากนั้นในเธรดใช้ local.session สำหรับทุกคำขอ

⚠️ ข้อควรระวัง: อย่าส่งออบเจกต์ Session หนึ่งระหว่างเธรดเป็นทรัพยากรที่ใช้ร่วมกันเด็ดขาด ถึงแม้ดูเหมือนคำขอจะเรียงกันตามลำดับ แต่ตัวจัดตารางอาจสลับเธรดในจังหวะที่แย่ที่สุด และคุณจะได้คุกกี้ที่ปนกัน แต่ละเธรดต้องมีออบเจกต์ของตัวเอง

การหมุนเวียนภายในตรรกะ

เมื่อมีการหมุนเวียน IP และคุณต้องการที่อยู่ใหม่ ให้ทำแบบนี้ จบเซสชันเชิงตรรกะปัจจุบัน: หากเซิร์ฟเวอร์ผูกกับ IP อย่างเข้มงวด ก็แค่สร้างออบเจกต์ Session ใหม่กับพร็อกซีใหม่แล้วเริ่มต้นจากศูนย์ - ล็อกอินใหม่ หากเซิร์ฟเวอร์ยอมรับการเปลี่ยนที่อยู่ คุณสามารถย้ายคุกกี้ได้ ซึ่งจะพูดถึงในขั้นตอนการเก็บสถานะ

การตรวจสอบ: รันสองเซสชันกับพร็อกซีที่ต่างกัน ล็อกอินในแต่ละเซสชันบนบริการทดสอบที่แสดง IP และคุกกี้ของคุณ ตรวจสอบให้แน่ใจว่าแต่ละเซสชันเห็น IP และชุดคุกกี้ของตัวเอง หากข้อมูลไม่ปนกัน แสดงว่าการแยกทำงานถูกต้อง

ขั้นตอนที่ 3: ทำแบบเดียวกันบน Node.js

เป้าหมายของขั้นตอนนี้: สร้างโครงสร้างเทียบเท่าบน JavaScript โดยใช้ axios, tough-cookie และพร็อกซีเอเจนต์

ในระบบนิเวศของ Node.js ไม่มีออบเจกต์ระดับ Session สำเร็จรูป เราจึงต้องประกอบมันจากสามส่วน ที่เก็บคุกกี้จะมาจาก tough-cookie การเชื่อมต่อผ่านพร็อกซีจะใช้เอเจนต์ ส่วนคำขอใช้ axios

ประกอบคอนเทนเนอร์

  1. นำเข้าคลาส CookieJar จากไลบรารี tough-cookie
  2. นำเข้าฟังก์ชันสร้างพร็อกซีเอเจนต์จากไลบรารี https-proxy-agent
  3. นำเข้า axios
  4. สร้างฟังก์ชัน makeClient ที่รับที่อยู่พร็อกซีและคืนค่าออบเจกต์ที่ตั้งค่าไว้

ภายในฟังก์ชันสร้างอินสแตนซ์ที่เก็บใหม่: const jar = new CookieJar() สร้างพร็อกซีเอเจนต์โดยส่งที่อยู่ให้: const agent = new HttpsProxyAgent(ที่อยู่ของพร็อกซี) สร้างอินสแตนซ์ axios ด้วยการตั้งค่าผ่านเมธอด axios.create โดยส่ง httpsAgent เท่ากับ agent และ httpAgent เท่ากับ agent

เชื่อมต่อการทำงานกับคุกกี้อัตโนมัติ

axios เปล่า ๆ ไม่สามารถเก็บคุกกี้จากคำตอบลงในที่เก็บและดึงออกมาใช้สำหรับคำขอได้ มีสองวิธี

  1. วิธีแรก: ใช้ wrapper สำเร็จรูปที่เชื่อม axios และ tough-cookie ซึ่งติดตั้งเป็นแพ็กเกจแยก มันจะอ่านและเขียนคุกกี้ผ่านที่เก็บ jar ที่ส่งให้โดยอัตโนมัติ
  2. วิธีที่สอง: ทำด้วยตนเองผ่านตัวสกัดกั้นคำขอและคำตอบ ก่อนส่งคำขอ ดึงสตริงคุกกี้จากที่เก็บสำหรับที่อยู่ที่ต้องการแล้วใส่ในส่วนหัว Cookie หลังจากได้รับคำตอบ นำส่วนหัว Set-Cookie มาบันทึกแต่ละคุกกี้ลงในที่เก็บ

เคล็ดลับ: ตอนเริ่มต้นใช้ wrapper สำเร็จรูปก่อน - โอกาสผิดพลาดน้อยกว่า วิธีแบบมือไว้ใช้เมื่อต้องการควบคุมกระบวนการอย่างละเอียด เช่น บันทึกทุกคุกกี้

การแยกระหว่างงานแบบขนาน

ใน Node.js โมเดลต่างออกไป - ที่นี่ไม่มีเธรด แต่เป็นงานแบบอะซิงโครนัสในเธรดเหตุการณ์เดียว แต่หลักการเหมือนกัน: แต่ละเซสชันเชิงตรรกะมีออบเจกต์ client แยกของตัวเอง พร้อม jar และเอเจนต์ของตัวเอง

  1. สำหรับงานแบบขนานแต่ละงาน ให้เรียก makeClient แยกกัน
  2. เก็บ clients ในอาร์เรย์หรือแผนที่ โดยคีย์คือ ID ของงาน
  3. อย่าใช้ jar เดียวกันสำหรับหลาย clients พร้อมกันเด็ดขาด

⚠️ ข้อควรระวัง: ในโค้ดแบบอะซิงโครนัส คุณอาจเผลอแชร์ client หนึ่งระหว่างเชนของพรอมิสหลายเชนได้ง่าย ๆ แล้วคุกกี้จะเริ่มปนกันระหว่างเซสชันเชิงตรรกะ ตรวจสอบเสมอว่าแต่ละเชนใช้ client ของตัวเองที่สร้างด้วยการเรียก makeClient แยกกัน

การหมุนเวียนบน Node.js

ตรรกะเหมือนกับ Python เมื่อต้องการ IP ใหม่และบริการผูกเซสชันกับที่อยู่ - สร้าง client ใหม่กับพร็อกซีใหม่และ jar ใหม่เปล่า ๆ แล้วล็อกอินใหม่ เมื่อบริการยอมรับ - ย้ายเนื้อหาของ jar เก่าไปยัง client ใหม่กับเอเจนต์ใหม่

การตรวจสอบ: สร้าง clients สองตัวกับพร็อกซีต่างกัน ส่งคำขอไปยังบริการทดสอบที่แสดง IP และคุกกี้ ตรวจสอบว่า client แรกเห็น IP หนึ่งและคุกกี้ของตัวเอง ส่วน client ที่สองเห็นอีก IP หนึ่งและคุกกี้ของตัวเอง ต้องไม่มีการทับซ้อน

ขั้นตอนที่ 4: เก็บสถานะระหว่างการรัน

เป้าหมายของขั้นตอนนี้: เรียนรู้วิธีบันทึกคุกกี้ลงดิสก์และกู้คืนเมื่อรันโปรแกรมครั้งถัดไป โดยคำนึงถึงอายุของคุกกี้

บ่อยครั้งที่ต้องหยุดสคริปต์แล้วรันทีหลัง โดยไม่สูญเสียการล็อกอิน ในการนี้ต้องซีเรียลไลซ์คุกกี้ - แปลงเป็นข้อความและบันทึกลงไฟล์หรือฐานข้อมูล

การซีเรียลไลซ์ใน Python

ออบเจกต์ CookieJar จาก requests สามารถบันทึกได้หลายวิธี วิธีที่พกพาสะดวกที่สุดคือรวบรวมคุกกี้เป็นพจนานุกรมง่าย ๆ แล้วเขียนเป็นรูปแบบ JSON

  1. วนดูคุกกี้ทั้งหมดของออบเจกต์เซสชันผ่าน s.cookies
  2. สำหรับแต่ละคุกกี้ เก็บชื่อ ค่า โดเมน พาธ และวันหมดอายุ
  3. รวมเป็นลิสต์ของพจนานุกรม
  4. เขียนลิสต์ลงไฟล์ในรูปแบบ JSON

เมื่อกู้คืนให้ทำย้อนกลับ: อ่านไฟล์ วนดูรายการ และเพิ่มแต่ละคุกกี้ลงในออบเจกต์เซสชันใหม่ด้วยเมธอดการตั้งค่าคุกกี้ โดยระบุโดเมนและพาธ

เคล็ดลับ: เก็บ ID ของพร็อกซีหรืออย่างน้อยก็เครื่องหมายว่าคุกกี้เหล่านี้เป็นของเซสชันเชิงตรรกะใดควบคู่ไปกับคุกกี้ วิธีนี้คุณจะไม่กู้คืนคุกกี้ของคนอื่นกับ IP ที่ผิด และไม่ละเมิดกฎการจับคู่

การซีเรียลไลซ์ใน Node.js

ไลบรารี tough-cookie มีเมธอดซีเรียลไลซ์ในตัว ออบเจกต์ jar มีเมธอดแบบอะซิงโครนัสที่แปลงที่เก็บทั้งหมดเป็นออบเจกต์ JSON เมธอดย้อนกลับจะกู้คืน jar จากออบเจกต์นั้น

  1. เรียกเมธอดซีเรียลไลซ์ของที่เก็บแล้วรับออบเจกต์
  2. แปลงออบเจกต์เป็นสตริงแล้วบันทึกลงไฟล์
  3. เมื่อเริ่มต้น ให้อ่านไฟล์ แยกสตริงกลับเป็นออบเจกต์
  4. กู้คืน jar ด้วยเมธอดดีซีเรียลไลซ์ โดยส่งออบเจกต์

วิธีนี้สะดวกกว่าใน Python เพราะ tough-cookie เก็บฟิลด์ที่จำเป็นทั้งหมดไว้เอง รวมถึงวันหมดอายุและแฟล็กความปลอดภัย

อายุของคุกกี้

คุกกี้ทุกตัวมีวันหมดอายุ มีคุกกี้แบบเซสชัน - มันอยู่จนกว่าจะปิดเบราว์เซอร์และไม่มีวันที่ชัดเจน มีแบบถาวร - มีวันหมดอายุที่แน่นอน การบันทึกลงดิสก์ควรทำกับคุกกี้แบบถาวรที่ยังไม่หมดอายุเท่านั้น คุกกี้แบบเซสชันหลังรีสตาร์ทมักใช้ไม่ได้บนเซิร์ฟเวอร์แล้ว

  1. ก่อนบันทึก ให้ตรวจสอบวันหมดอายุของแต่ละคุกกี้
  2. ทิ้งคุกกี้ที่หมดอายุแล้ว
  3. เมื่อกู้คืน ให้ตรวจสอบวันหมดอายุอีกครั้งและอย่าโหลดคุกกี้ที่หมดอายุแล้ว

เมื่อไหร่ควรทิ้งสถานะทิ้งไปง่าย ๆ

ไม่เสมอไปที่ควรยึดติดกับคุกกี้ที่บันทึกไว้ บางครั้งการเริ่มต้นใหม่ก็เร็วกว่าและเชื่อถือได้มากกว่า

  • หากเวลาผ่านไปนานจากการรันครั้งล่าสุด - เซสชันบนเซิร์ฟเวอร์คงหมดอายุแล้ว ไม่มีอะไรให้กู้คืน
  • หากเซิร์ฟเวอร์คืนข้อผิดพลาดการยืนยันตัวตนในคำขอแรกด้วยคุกกี้ที่กู้คืนมา - ทิ้งมันแล้วล็อกอินใหม่
  • หากไม่แน่ใจในความสมบูรณ์ของไฟล์สถานะ - เริ่มจากศูนย์ดีกว่ามานั่งดีบั๊กพฤติกรรมแปลก ๆ

⚠️ ข้อควรระวัง: ไฟล์ที่มีคุกกี้และโทเค็นมีข้อมูลการเข้าถึง เก็บไว้ในที่ปลอดภัย อย่าใส่ในรีโพซิทอรีสาธารณะ อย่าส่งผ่านช่องทางที่ไม่ปลอดภัย การรั่วไหลของไฟล์แบบนี้เท่ากับการรั่วไหลของสิทธิ์เข้าถึงบัญชี

การตรวจสอบ: บันทึกสถานะ ปิดโปรแกรมทั้งหมด เปิดใหม่ กู้คืนสถานะ แล้วส่งคำขอที่ต้องมีการล็อกอิน หากเซิร์ฟเวอร์ตอบเหมือนผู้ใช้ที่ล็อกอินอยู่ แสดงว่าการบันทึกทำงาน หากถูกออกจากระบบ ให้ตรวจสอบวันหมดอายุและการกู้คืนโดเมนและพาธให้ถูกต้อง

ขั้นตอนที่ 5: วิเคราะห์ข้อผิดพลาดทั่วไปในสถาปัตยกรรม

เป้าหมายของขั้นตอนนี้: เจาะลึกข้อผิดพลาดหลักสามข้อ เพื่อให้คุณรู้จักมันในโค้ดและไม่ทำซ้ำ

ข้อผิดพลาดข้อแรก: ใช้ CookieJar ร่วมกันสำหรับทุกพร็อกซี

นี่คือต้นตอของปัญหา นักพัฒนาสร้างที่เก็บคุกกี้หนึ่งอันแล้วใส่พร็อกซีต่าง ๆ ลงไป คิดว่าจะประหยัด เกิดอะไรขึ้น: คุกกี้จากเซสชันบน IP แรกหลุดไปในคำขอบน IP ที่สอง เซิร์ฟเวอร์เห็นคุกกี้ที่สร้างภายใต้ที่อยู่อื่น แล้วอาจรีเซ็ตเซสชันหรือถือว่าพฤติกรรมน่าสงสัย

วิธีแก้ง่าย ๆ: แต่ละพร็อกซีต้องมีที่เก็บคุกกี้ของตัวเอง ไม่มีข้อยกเว้น เราใส่สิ่งนี้ไว้ในขั้นตอนโค้ดแล้ว: แยก Session หรือแยก client พร้อม jar แยกสำหรับแต่ละเซสชันเชิงตรรกะ

ข้อผิดพลาดข้อสอง: race condition ในคำขอแบบขนาน

Race condition คือเมื่อสองการทำงานเข้าถึงข้อมูลเดียวกันพร้อมกันและรบกวนกัน หากสองเธรดเขียนลง CookieJar ตัวเดียวกัน การเขียนหนึ่งอาจทับอีกการเขียน ผลลัพธ์: คุกกี้บางส่วนหายไปแบบสุ่ม และบั๊กเกิดเป็นครั้งคราว ซึ่งดีบั๊กได้ยากมาก

  1. ให้แต่ละเธรดมีเซสชันของตัวเองผ่านข้อมูลเฉพาะเธรด อย่างที่เราอธิบายไว้
  2. ในโค้ดแบบอะซิงโครนัส อย่าแชร์ client หนึ่งระหว่างเชนงานอิสระ
  3. หากจำเป็นต้องใช้ออบเจกต์ร่วมกันด้วยเหตุผลบางประการ ให้ใช้ล็อกเพื่อให้มีเพียงเธรดเดียวที่ทำงานกับมันในเวลาใดเวลาหนึ่ง

เคล็ดลับ: วิธีที่ดีที่สุดในการหลีกเลี่ยง race condition คือการไม่มีข้อมูลที่เปลี่ยนแปลงร่วมกันเลย การแยกตามเซสชันเชิงตรรกะแก้ปัญหาที่ต้นเหตุ: หากข้อมูลไม่ใช้ร่วมกัน ก็ไม่มีทางเกิด race condition

ข้อผิดพลาดข้อสาม: การสูญเสีย Set-Cookie ระหว่างการเปลี่ยนเส้นทาง

เมื่อเซิร์ฟเวอร์ตอบกลับด้วยการเปลี่ยนเส้นทาง มันมักจะตั้งค่าคุกกี้สำคัญในคำตอบเดียวกันผ่านส่วนหัว Set-Cookie การตั้งค่าไคลเอนต์บางแบบเมื่อทำตามรีไดเรกต์อัตโนมัติจะทำคุกกี้เหล่านี้หาย - พวกมันไม่เข้าสู่ที่เก็บ

  1. ตรวจสอบว่าไคลเอนต์ของคุณบันทึกคุกกี้ในทุกขั้นของห่วงโซ่รีไดเรกต์ ไม่ใช่แค่คำตอบสุดท้าย
  2. ใน requests ทำงานตามค่าเริ่มต้นเมื่อใช้ออบเจกต์ Session - คุกกี้จะถูกเก็บตลอดทาง ตรวจสอบว่าคุณไม่ได้ปิดการติดตามรีไดเรกต์โดยไม่จำเป็น
  3. ใน axios เมื่อจัดการคุกกี้ด้วยตนเอง ให้ประมวลผล Set-Cookie ในทุกคำตอบระหว่างทาง หากใช้ wrapper ให้ตรวจสอบว่ามันดักจับรีไดเรกต์หรือไม่

⚠️ ข้อควรระวัง: หากการล็อกอินผ่าน แต่คำขอถัดไปถูกออกจากระบบ สาเหตุที่พบบ่อยคือคุกกี้ที่หายไประหว่างรีไดเรกต์ เปิดการบันทึกส่วนหัว Set-Cookie ทั้งหมด แล้วดูว่าคุกกี้ที่คาดหวังทั้งหมดไปถึงที่เก็บหรือไม่

การตรวจสอบ: ค้นหาการกระทำบนบริการเป้าหมายที่ทำให้เกิดรีไดเรกต์ เช่น การเข้าสู่ระบบผ่านฟอร์ม ตามห่วงโซ่และเปรียบเทียบคุกกี้หลังแต่ละขั้น คุกกี้ที่ออกทั้งหมดควรอยู่ในที่เก็บของคุณ หากตัวไหนหายไป แสดงว่าคุณเจอจุดรั่วแล้ว

ขั้นตอนที่ 6: รวมทุกอย่างเป็นกระบวนการทำงาน

เป้าหมายของขั้นตอนนี้: รวมสิ่งที่เรียนรู้เป็นกระบวนการทำงานที่คาดเดาได้ตั้งแต่เริ่มต้นจนถึงการหมุนเวียน

ตอนนี้คุณมีรายละเอียดครบแล้ว เรามารวมเป็นขั้นตอนการทำงานที่ทำซ้ำได้

  1. นำพร็อกซีจากพูลของคุณและสร้างเซสชันเชิงตรรกะแบบแยกสำหรับมัน - Session ใน Python หรือ client ใน Node.js
  2. หากมีสถานะที่บันทึกไว้สำหรับเซสชันเชิงตรรกะนี้และยังไม่หมดอายุ - กู้คืนคุกกี้ หากไม่ ก็ล็อกอินใหม่
  3. ส่งคำขอที่ต้องการผ่านออบเจกต์ของเซสชันนี้ คุกกี้จะสะสมโดยอัตโนมัติ
  4. บันทึกสถานะลงดิสก์เป็นระยะ ๆ เพื่อไม่ให้เสียความคืบหน้าเมื่อเกิดข้อขัดข้อง
  5. เมื่อถึงเวลาหมุนเวียน IP ให้จบเซสชันเชิงตรรกะอย่างถูกต้อง
  6. หากบริการผูกกับ IP อย่างเข้มงวด - เริ่มเซสชันเชิงตรรกะใหม่จากศูนย์บนที่อยู่ใหม่
  7. หากบริการยอมรับ - สร้างคอนเทนเนอร์ใหม่กับพร็อกซีใหม่แล้วย้ายคุกกี้จากอันเก่าไป

เคล็ดลับ: จดบันทึกเหตุการณ์: เมื่อใดที่สร้างเซสชัน ใช้ IP ใด เมื่อใดที่หมุนเวียน มีการถูกออกจากระบบหรือไม่ บันทึกแบบนี้จะเผยรูปแบบภายในห้านาที ซึ่งไม่งั้นคุณอาจใช้เวลาค้นหาหลายชั่วโมง

การตรวจสอบ: รันรอบเต็ม: สร้างเซสชัน ล็อกอิน ทำหลาย ๆ อย่าง บันทึก หมุนเวียน ทำต่อ ตรวจสอบว่าในแต่ละขั้นสถานะทำตัวตามคาด และการถูกออกจากระบบเกิดขึ้นเมื่อคุณคาดหวังเท่านั้น

ตรวจสอบผลลัพธ์: เช็กลิสต์สุดท้าย

ไล่ตามรายการนี้ หากทำครบทุกข้อ ระบบของคุณทำงานอย่างถูกต้อง

  • แต่ละเซสชันเชิงตรรกะมีออบเจกต์คอนเทนเนอร์แยกพร้อมที่เก็บคุกกี้ของตัวเอง
  • แต่ละคอนเทนเนอร์ผูกกับพร็อกซีหนึ่งตัวตลอดอายุของเซสชัน
  • ไม่มีจุดใดที่คุกกี้ของเซสชันหนึ่งสามารถไปอยู่อีกเซสชันหนึ่งได้
  • ในโค้ดแบบหลายเธรด แต่ละเธรดใช้เซสชันของตัวเองผ่านข้อมูลเฉพาะเธรด
  • ในโค้ดแบบอะซิงโครนัส แต่ละเชนอิสระมี client ของตัวเอง
  • คุกกี้ถูกเก็บอย่างถูกต้องในทุกขั้นของรีไดเรกต์
  • สถานะถูกบันทึกและกู้คืนระหว่างการรัน โดยคำนึงถึงวันหมดอายุ
  • เมื่อเปลี่ยน IP เซสชันเชิงตรรกะจะเริ่มใหม่หรือย้ายคุกกี้อย่างตั้งใจ
  • ไฟล์ที่มีคุกกี้และโทเค็นถูกเก็บอย่างปลอดภัย

วิธีทดสอบ

  1. หาบริการทดสอบที่แสดง IP ปัจจุบันและคุกกี้ที่ส่งมา
  2. สร้างสองเซสชันกับพร็อกซีต่างกันและตรวจสอบว่าข้อมูลแยกจากกันโดยสิ้นเชิง
  3. ล็อกอิน บันทึกสถานะ รีสตาร์ทโปรแกรม กู้คืน - ตรวจสอบว่าการล็อกอินยังใช้งานได้
  4. จำลองการหมุนเวียนและสังเกตว่าเซสชันมีพฤติกรรมอย่างไร

ตัวชี้วัดความสำเร็จ: ข้อมูลของเซสชันต่าง ๆ ไม่ปนกัน การถูกออกจากระบบเกิดขึ้นเฉพาะเมื่อเซิร์ฟเวอร์ผูกกับ IP อย่างเข้มงวด สถานะที่กู้คืนใช้งานได้ และไม่มี race condition ในการทำงานแบบขนาน

ข้อผิดพลาดทั่วไปและวิธีแก้ไข

ปัญหา: หลังเปลี่ยน IP ผู้ใช้ถูกออกจากระบบ สาเหตุ: เซิร์ฟเวอร์ผูกเซสชันกับที่อยู่อย่างเข้มงวด วิธีแก้: อย่าเปลี่ยน IP ภายในเซสชันเชิงตรรกะเดียว และเมื่อจำเป็นต้องเปลี่ยน ให้เริ่มเซสชันใหม่บนที่อยู่ใหม่

ปัญหา: คุกกี้ของเซสชันต่าง ๆ ปนกัน สาเหตุ: ใช้ CookieJar ร่วมกันสำหรับหลายพร็อกซี วิธีแก้: ให้แต่ละเซสชันเชิงตรรกะมีที่เก็บแยกกัน และอย่าใช้ร่วมกันเด็ดขาด

ปัญหา: บั๊กเกิดเป็นครั้งคราวเมื่อทำงานแบบขนาน สาเหตุ: race condition ในการเขียนลงออบเจกต์ร่วมจากหลายเธรด วิธีแก้: แยกเซสชันตามเธรดด้วยข้อมูลเฉพาะเธรด หรือใช้ล็อก

ปัญหา: การล็อกอินผ่าน แต่หลุดทันที สาเหตุ: คุกกี้หายระหว่างรีไดเรกต์ วิธีแก้: ตรวจสอบการเก็บคุกกี้ในทุกขั้นของห่วงโซ่การเปลี่ยนเส้นทางและเปิดการบันทึก Set-Cookie

ปัญหา: สถานะที่กู้คืนมาใช้งานไม่ได้ สาเหตุ: บันทึกคุกกี้ที่หมดอายุหรือแบบเซสชันไว้ หรือระบุโดเมนและพาธไม่ถูกต้อง วิธีแก้: บันทึกเฉพาะคุกกี้แบบถาวรที่ยังมีอายุ และกู้คืนด้วยโดเมนและพาธที่ถูกต้อง

ปัญหา: โทเค็น CSRF ใช้ไม่ได้ตลอด สาเหตุ: คุกกี้เซสชันที่โทเค็นผูกอยู่หายไป วิธีแก้: ก่อนอื่นทำให้คุกกี้เซสชันครบถ้วนก่อน โทเค็นจะถูกดึงกลับมาโดยอัตโนมัติ

ปัญหา: JWT ใช้ไม่ได้หลังการหมุนเวียน สาเหตุ: บริการนั้นผูกโทเค็นกับ IP ฝั่งตัวเอง วิธีแก้: อย่าเปลี่ยน IP ตราบที่โทเค็นยังมีอายุ หรือขอโทเค็นใหม่บนที่อยู่ใหม่

ความสามารถเพิ่มเติมและการปรับแต่งประสิทธิภาพ

เมื่อโครงสร้างพื้นฐานทำงานได้ ก็สามารถเสริมความแข็งแกร่งได้

พูลของเซสชันที่เตรียมไว้

แทนที่จะสร้างเซสชันทุกครั้ง ให้เก็บพูลของเซสชันเชิงตรรกะที่เตรียมไว้และล็อกอินแล้ว แต่ละเซสชันมีพร็อกซีของตัวเอง หยิบเซสชันว่างไปใช้ แล้วคืนกลับเข้าพูล วิธีนี้ทำงานเร็วขึ้นเพราะไม่ต้องล็อกอินซ้ำโดยไม่จำเป็น

การตรวจสอบความมีชีวิตอัตโนมัติ

เพิ่มฟังก์ชันที่ส่งคำขอเบา ๆ ไปยังบริการและตรวจสอบว่าเซสชันยังมีชีวิตอยู่หรือไม่ หากเซิร์ฟเวอร์ตอบเหมือนผู้ไม่ได้รับอนุญาต - เซสชันจะถูกทำเครื่องหมายให้ล็อกอินใหม่ วิธีนี้คุณจะจับการหมดอายุได้ก่อนที่มันจะทำลายปฏิบัติการสำคัญ

เคล็ดลับ: ตรวจสอบความมีชีวิตไม่ใช่ก่อนทุกคำขอ แต่ตามกำหนดเวลาหรือหลังจากหยุดนานเกินไป การตรวจสอบบ่อยเกินไปสร้างภาระโดยไม่จำเป็นและไม่เกิดประโยชน์

ที่เก็บสถานะแบบรวมศูนย์

สำหรับโปรเจกต์ขนาดใหญ่ แทนที่จะใช้ไฟล์ ให้ใช้ฐานข้อมูลเป็นที่เก็บคุกกี้ คีย์คือ ID ของเซสชันเชิงตรรกะ ค่าคือสถานะที่ซีเรียลไลซ์แล้ว วิธีนี้ปรับขนาดได้ง่ายกว่าและเก็บได้ปลอดภัยกว่า

เมตริกและการสังเกตได้

นับจำนวนครั้งที่ถูกออกจากระบบ จำนวนเซสชันที่ต้องสร้างใหม่ และความถี่ที่การกู้คืนสำเร็จ ตัวเลขเหล่านี้บ่งบอกสุขภาพของระบบและบอกว่าจุดใดถูกตั้งค่าไม่เหมาะสม

FAQ: คำถามที่พบบ่อย

จำเป็นต้องสร้างออบเจกต์เซสชันใหม่ทุกครั้งที่เปลี่ยน IP หรือไม่? หากบริการตรวจสอบที่อยู่อย่างเข้มงวด - ใช่ เพราะเซสชันเก่าบน IP ใหม่จะไม่ถูกรับอยู่ดี หากบริการยอมรับ - สามารถย้ายคุกกี้ไปยังคอนเทนเนอร์ใหม่กับพร็อกซีใหม่และทำต่อได้

สามารถใช้พร็อกซีเดียวสำหรับหลายเซสชันเชิงตรรกะได้หรือไม่? ในแง่โค้ดทำได้ แต่แต่ละเซสชันเชิงตรรกะต้องมีที่เก็บคุกกี้แยกกัน สิ่งที่ใช้ร่วมกันได้คือการตั้งค่าการเชื่อมต่อเท่านั้น แต่ไม่ใช่สถานะ

ทำไมไม่เก็บคุกกี้ทั้งหมดในที่เดียวแล้วกรองตามโดเมน? เพราะปัญหาไม่ได้อยู่ที่โดเมน แต่อยู่ที่การผูกกับเซสชันเชิงตรรกะและ IP ที่เฉพาะ คุกกี้ของเซสชันหนึ่งบนโดเมนหนึ่งไม่ควรไปอยู่อีกเซสชันหนึ่งบนโดเมนเดียวกัน

จะรู้ได้อย่างไรว่าบริการผูกเซสชันกับ IP หรือไม่? ทดลอง: ล็อกอินบน IP หนึ่ง เปลี่ยนที่อยู่แล้วส่งคำขอ หากถูกออกจากระบบ - อาจมีการผูก กลับไปที่ IP เดิม: หากกลับมาเป็นปกติ แสดงว่าเซิร์ฟเวอร์จำที่อยู่แรกได้

จะจัดการกับคุกกี้แบบเซสชันเมื่อบันทึกลงดิสก์อย่างไร? โดยทั่วไปไม่ควรบันทึก เพราะเซิร์ฟเวอร์ถือว่ามันใช้ไม่ได้หลังการเชื่อมต่อขาด ให้บันทึกเฉพาะคุกกี้แบบถาวรที่ยังมีอายุ

จะทำอย่างไรหากไลบรารีไม่บันทึกคุกกี้เองเมื่อรีไดเรกต์? ประมวลผลส่วนหัว Set-Cookie ด้วยตนเองในทุกคำตอบระหว่างทางของห่วงโซ่การเปลี่ยนเส้นทาง แล้วเก็บคุกกี้ลงในที่เก็บของคุณ

จำเป็นต้องใช้ล็อกหรือไม่หากแต่ละเธรดมีเซสชันของตัวเอง? ไม่จำเป็น หากข้อมูลไม่ใช้ร่วมกัน ก็ไม่มี race condition และไม่ต้องใช้ล็อก ล็อกจำเป็นเฉพาะเมื่อถูกบังคับให้เข้าถึงออบเจกต์เดียวกันร่วมกัน

สามารถเก็บสถานะที่กู้คืนได้นานแค่ไหน? จนกว่าเซิร์ฟเวอร์จะถือว่าเซสชันยังมีชีวิตอยู่เท่านั้น ระยะเวลาที่แน่นอนขึ้นอยู่กับบริการ วิธีที่ใช้ได้จริงคือตรวจสอบความมีชีวิตด้วยคำขอ มากกว่าจะเดาจากเวลา

อะไรสำคัญกว่า - เก็บคุกกี้หรือเก็บโทเค็น? ขึ้นอยู่กับกลไกการยืนยันตัวตนของบริการ บางครั้งแค่โทเค็นก็พอ บางครั้งต้องใช้คุกกี้ครบชุด ปลอดภัยที่สุดคือเก็บสถานะทั้งหมดทั้งชุด แล้วคุณจะไม่พลาดสิ่งที่จำเป็น

สามารถย้ายคุกกี้ระหว่าง Python และ Node.js ได้หรือไม่? ได้ หากบันทึกในรูปแบบกลางที่เป็นกลาง เช่น JSON ที่มีฟิลด์ชื่อ ค่า โดเมน พาธ และวันหมดอายุ จากนั้นระบบใดก็อ่านได้

บทสรุป

มาสรุปสิ่งที่คุณได้เรียนรู้กัน คุณเข้าใจแล้วว่าหลังเปลี่ยน IP การถูกออกจากระบบไม่ได้เกิดจากตัวการเปลี่ยนเอง แต่เกิดจากการตรวจสอบของเซิร์ฟเวอร์และข้อผิดพลาดในสถาปัตยกรรมของคุณ คุณได้รู้ว่าคุกกี้, CSRF, JWT โดยตัวมันเองไม่ผูกกับที่อยู่ แต่บริการเฉพาะเป็นผู้เพิ่มการผูก คุณได้ซึมซับกฎหลัก: หนึ่งเซสชันเชิงตรรกะเท่ากับหนึ่งชุดคุกกี้เท่ากับหนึ่ง IP

จากนั้นคุณได้เขียนโค้ดที่ใช้งานได้จริง บน Python - ผ่านออบเจกต์ Session แยกกับ CookieJar ของตัวเองสำหรับแต่ละพร็อกซี และการแยกตามเธรด บน Node.js - ผ่านการรวมกันของ axios, tough-cookie และพร็อกซีเอเจนต์กับ client แยกสำหรับแต่ละเซสชันเชิงตรรกะ คุณได้เรียนรู้การบันทึกสถานะระหว่างการรัน การคำนึงถึงวันหมดอายุของคุกกี้ และการรู้ว่าเมื่อไหร่ควรทิ้งสถานะทิ้งไป

คุณได้วิเคราะห์ข้อผิดพลาดร้ายแรงสามข้อ: การใช้ CookieJar ร่วมกัน, race condition ในการทำงานแบบขนาน และการสูญเสีย Set-Cookie ระหว่างรีไดเรกต์ และตอนนี้คุณมีเช็กลิสต์ก่อนขึ้นโปรดักชันที่จะไม่ปล่อยโซลูชันที่ยังไม่สมบูรณ์ออกไป

ควรทำอะไรต่อ

เริ่มจากเล็ก ๆ ใช้หนึ่งสถานการณ์จริง สร้างเซสชันเชิงตรรกะแบบแยกสำหรับมัน และตรวจสอบว่าสถานะไม่หายไป จากนั้นเพิ่มการบันทึกลงดิสก์ จากนั้นขยายไปหลายเซสชัน ค่อย ๆ ทำทีละขั้น ตรวจสอบผลลัพธ์ในแต่ละขั้น

จะพัฒนาไปทางไหนต่อ

ต่อไปควรเจาะลึกเรื่องการสังเกตได้: ตั้งค่าเมตริกความมีชีวิตของเซสชันและการบันทึกเหตุการณ์ จากนั้นศึกษาเรื่องการย้ายสถานะอย่างมีสติเมื่อบริการยอมรับการเปลี่ยนที่อยู่ สุดท้ายสร้างพูลของเซสชันที่เตรียมไว้เพื่อเพิ่มความเร็ว แต่ละขั้นเหล่านี้ทำให้ระบบของคุณแข็งแรงและคาดเดาได้มากขึ้น คุณทำได้แน่นอน - คุณเข้าใจหลักการแล้ว ที่เหลือคือเรื่องของการฝึกฝน