บทช่วยสอนสำหรับวิศวกรรมย้อนกลับ API ส่วนตัวของซอฟต์แวร์ของคุณ: การแฮ็กโซฟาของคุณ
เผยแพร่แล้ว: 2022-03-11การเดินทางคือสิ่งที่ฉันหลงใหล และฉันเป็นแฟนตัวยงของ Couchsurfing Couchsurfing เป็นชุมชนนักเดินทางทั่วโลก ซึ่งคุณสามารถหาที่พักหรือแชร์บ้านของคุณเองกับนักเดินทางคนอื่นๆ ยิ่งไปกว่านั้น Couchsurfing ช่วยให้คุณเพลิดเพลินไปกับประสบการณ์การเดินทางที่แท้จริงในขณะที่มีปฏิสัมพันธ์กับคนในท้องถิ่น ฉันมีส่วนร่วมกับชุมชน Couchsurfing มานานกว่า 3 ปี ฉันเข้าร่วมมีตติ้งในตอนแรก และในที่สุดฉันก็สามารถจัดคนได้ ช่างเป็นการเดินทางที่น่าทึ่งจริงๆ! ฉันได้พบผู้คนที่น่าทึ่งมากมายจากทั่วทุกมุมโลกและได้รู้จักเพื่อนมากมาย ประสบการณ์ทั้งหมดนี้เปลี่ยนชีวิตฉันอย่างแท้จริง
ฉันได้เป็นเจ้าภาพให้กับนักเดินทางจำนวนมาก มากกว่าที่ฉันเคยเล่นจริงๆ ขณะอาศัยอยู่ในสถานที่ท่องเที่ยวสำคัญแห่งหนึ่งในเฟรนช์ ริเวียร่า ฉันได้รับคำขอโซฟาจำนวนมหาศาล (มากถึง 10 ครั้งต่อวันในช่วงไฮซีซั่น) ในฐานะนักพัฒนาแบ็คเอนด์อิสระ ฉันสังเกตเห็นทันทีว่าปัญหาที่เกิดขึ้นกับเว็บไซต์ couchsurfing.com คือมันไม่สามารถจัดการกับกรณีที่มี "ภาระงานสูง" ดังกล่าวได้อย่างเหมาะสม ไม่มีข้อมูลเกี่ยวกับความพร้อมใช้งานของโซฟาของคุณ - เมื่อคุณได้รับคำขอโซฟาใหม่ คุณไม่สามารถแน่ใจได้ว่าคุณกำลังโฮสต์ใครบางคนในขณะนั้นหรือไม่ ควรมีการแสดงคำขอที่ยอมรับและรอดำเนินการของคุณเป็นภาพ เพื่อให้คุณสามารถจัดการได้ดียิ่งขึ้น นอกจากนี้ หากคุณสามารถทำให้โซฟาของคุณมีห้องว่างต่อสาธารณะได้ คุณสามารถหลีกเลี่ยงคำขอโซฟาที่ไม่จำเป็นได้ เพื่อให้เข้าใจสิ่งที่ฉันคิดได้ดีขึ้น ให้ดูที่ปฏิทิน Airbnb
บริษัทจำนวนมากขึ้นชื่อเรื่องการไม่ฟังผู้ใช้ของตน เมื่อทราบประวัติของ Couchsurfing ฉันก็วางใจไม่ได้ว่าพวกเขาจะใช้ฟีเจอร์นี้ในเร็วๆ นี้ ตั้งแต่เว็บไซต์กลายเป็นบริษัทที่แสวงหาผลกำไร ชุมชนก็เสื่อมโทรมลง เพื่อให้เข้าใจสิ่งที่ฉันพูดถึงมากขึ้น ขอแนะนำให้อ่านบทความสองบทความนี้:
- http://www.nithincoca.com/2013/03/27/the-rise-and-fall-of-couchsurfing/
- http://mechanicalbrain.wordpress.com/2013/03/04/couchsurfing-a-sad-end-to-a-great-idea/
ฉันรู้ว่าสมาชิกในชุมชนจำนวนมากยินดีที่จะมีฟังก์ชันนี้ ดังนั้นฉันจึงตัดสินใจสร้างแอปเพื่อแก้ปัญหานี้ ปรากฎว่าไม่มี Couchsurfing API สาธารณะที่พร้อมใช้งาน นี่คือคำตอบที่ฉันได้รับจากทีมสนับสนุนของพวกเขา:
“น่าเสียดายที่เราต้องแจ้งให้คุณทราบว่า API ของเราไม่ได้เป็นแบบสาธารณะจริงๆ และไม่มีแผนที่จะเผยแพร่ในขณะนี้”
บุกเข้าไปในโซฟาของฉัน
ถึงเวลาที่จะใช้เทคนิควิศวกรรมย้อนกลับของซอฟต์แวร์ที่ฉันโปรดปรานเพื่อเจาะเข้าไปใน Couchsurfing.com ฉันคิดว่าแอพมือถือของพวกเขาต้องใช้ API บางประเภทเพื่อสืบค้นแบ็กเอนด์ ดังนั้น ฉันต้องสกัดกั้นคำขอ HTTP ที่มาจากแอปมือถือไปยังแบ็กเอนด์ เพื่อจุดประสงค์นั้น ฉันตั้งค่าพร็อกซีในเครือข่ายท้องถิ่น และเชื่อมต่อ iPhone ของฉันกับมันเพื่อสกัดกั้นคำขอ HTTP ด้วยวิธีนี้ ฉันสามารถค้นหาจุดเข้าใช้งานของ API ส่วนตัวและหารูปแบบเพย์โหลด JSON ได้
ในที่สุดฉันก็สร้างเว็บไซต์ที่มีจุดประสงค์เพื่อช่วยผู้คนจัดการคำขอโซฟาของพวกเขา และแสดงปฏิทินความพร้อมสำหรับโซฟาให้นักเล่นกระดานโต้คลื่นดู ฉันเผยแพร่ลิงก์ไปที่ฟอรัมชุมชน (ซึ่งในความคิดของฉันมีการแบ่งกลุ่มค่อนข้างมาก และหาข้อมูลที่นั่นได้ยาก) แผนกต้อนรับส่วนใหญ่เป็นไปในเชิงบวก แม้ว่าบางคนจะไม่ชอบความคิดที่ว่าเว็บไซต์ต้องการข้อมูลรับรองของ couchsurfing.com ซึ่งเป็นเรื่องของความไว้วางใจจริงๆ
เว็บไซต์ทำงานในลักษณะนี้: คุณลงชื่อเข้าใช้เว็บไซต์ด้วยข้อมูลรับรองของ couchsurfing.com และหลังจากคลิกไม่กี่ครั้ง คุณจะได้รับโค้ด html ซึ่งคุณสามารถฝังลงในโปรไฟล์ของ couchsurfing.com และ voila - คุณมีปฏิทินที่อัปเดตโดยอัตโนมัติใน โปรไฟล์ของคุณ ด้านล่างนี้คือภาพหน้าจอของปฏิทินและนี่คือบทความเกี่ยวกับวิธีการสร้างปฏิทิน:
- https://github.com/nderkach/couchsurfing-python
ฉันได้สร้างคุณลักษณะที่ยอดเยี่ยมสำหรับ Couchsurfing และฉันคิดว่าพวกเขาจะชื่นชมงานของฉัน และอาจเสนอตำแหน่งให้ฉันในทีมพัฒนาของพวกเขา ฉันได้ส่งอีเมลไปที่ jobs (at) couchsurfing.com พร้อมลิงก์ไปยังเว็บไซต์ ประวัติย่อของฉัน และข้อมูลอ้างอิง ข้อความขอบคุณที่แขกคนหนึ่งของฉันทิ้งไว้บนโซฟาเซิร์ฟ:
สองสามวันต่อมาพวกเขาก็ติดตามความพยายามด้านวิศวกรรมย้อนกลับของฉัน ในการตอบกลับนั้นชัดเจนว่าสิ่งเดียวที่พวกเขากังวลคือความปลอดภัยของตนเอง ดังนั้นพวกเขาจึงขอให้ฉันลบโพสต์ในบล็อกที่ฉันเขียนเกี่ยวกับ API และเว็บไซต์ในที่สุด ฉันลบโพสต์ทันที เนื่องจากไม่ได้ตั้งใจที่จะละเมิดเงื่อนไขการใช้งานและค้นหาข้อมูลประจำตัวของผู้ใช้ แต่เพื่อช่วยชุมชนของ couchsurfing ฉันมีความรู้สึกว่าถูกปฏิบัติเหมือนเป็นอาชญากร และบริษัทเน้นย้ำว่าเว็บไซต์ของฉันต้องการข้อมูลประจำตัวของผู้ใช้เท่านั้น
ฉันเสนอให้แอปของฉันแก่พวกเขาฟรี พวกเขาสามารถโฮสต์บนสภาพแวดล้อมของพวกเขาและเชื่อมต่อผ่านการตรวจสอบ Facebook ท้ายที่สุด มันเป็นคุณสมบัติที่ยอดเยี่ยม และชุมชนก็ต้องการมัน นี่คือความละเอียดสุดท้ายที่ฉันได้รับ:
“เรากำลังกลับมาทำสิ่งต่างๆ ที่นี่หลังวันหยุด และต้องการติดตามผล
เราได้พูดคุยกันเป็นการภายในเกี่ยวกับแอปพลิเคชันของคุณ และวิธีที่เราจะให้เกียรติความคิดสร้างสรรค์และความคิดริเริ่มที่แสดงออกมา โดยที่ไม่กระทบต่อความเป็นส่วนตัวและความปลอดภัยของข้อมูลผู้ใช้ Couchsurfing เมื่อพวกเขาป้อนข้อมูลประจำตัวในไซต์บุคคลที่สาม
ปฏิทินได้อุดช่องโหว่บนไซต์ของเราอย่างชัดเจน ซึ่งเป็นคุณลักษณะที่เป็นส่วนหนึ่งของโครงการขนาดใหญ่ที่เรากำลังดำเนินการอยู่ในขณะนี้
แต่ปัญหาในการรวบรวมชื่อผู้ใช้และรหัสผ่านยังคงอยู่ เราไม่สามารถหาวิธีง่าย ๆ ในการตั้งค่าเพื่อให้เราสามารถโฮสต์หรือสนับสนุนสิ่งนั้นจากฝั่งของเราโดยไม่ให้คุณเข้าถึงข้อมูลนั้นหรือให้ไซต์ของคุณถูกมองว่าเป็นผลงานของเรา
API ที่มีอยู่ในปัจจุบันจะถูกแทนที่ด้วยเวอร์ชันที่ต้องการการตรวจสอบสิทธิ์/การอนุญาตจากแอปพลิเคชันที่เข้าถึงได้ในเร็วๆ นี้”
วันนี้ในขณะที่ฉันกำลังเขียนบทช่วยสอนเกี่ยวกับซอฟต์แวร์วิศวกรรมย้อนกลับ (หนึ่งปีหลังจากเหตุการณ์นี้) คุณลักษณะปฏิทินยังไม่ได้ใช้งานบน Couchsurfing
กลับไปสู่ความไร้เดียงสา - แฮ็คโซฟาของฉันอีกครั้ง
เมื่อไม่กี่สัปดาห์ก่อน ฉันได้รับแรงบันดาลใจให้เขียนบทความเกี่ยวกับเทคนิคในการทำวิศวกรรมย้อนกลับ API ส่วนตัว โดยปกติ ฉันตัดสินใจสรุปบทความก่อนหน้าที่ฉันเขียนเกี่ยวกับหัวข้อนี้ และเพิ่มรายละเอียดอีกเล็กน้อย เมื่อฉันเริ่มเขียนบทความใหม่ ฉันต้องการแสดงกระบวนการวิศวกรรมย้อนกลับด้วย API ล่าสุด และนำโครงอื่นเข้าสู่การแฮ็ก API จากประสบการณ์ก่อนหน้านี้ของฉัน และความจริงที่ว่า Couchsurfing เพิ่งประกาศเว็บไซด์และแอพมือถือใหม่อย่างสมบูรณ์ http://blog.couchsurfing.com/the-future-of-couchsurfing-is-on-the-way/ ฉันเคย ตัดสินใจแฮ็ค API อีกครั้ง
ทำไมฉันถึงทำกระบวนการวิศวกรรมย้อนกลับนี้ อย่างแรกเลย เป็นเรื่องสนุกมากที่ซอฟต์แวร์วิศวกรรมย้อนกลับโดยทั่วไป สิ่งที่ฉันชอบเป็นพิเศษเกี่ยวกับเรื่องนี้คือ มันไม่ได้เกี่ยวข้องกับทักษะทางเทคนิคของคุณเท่านั้น แต่ยังรวมถึงสัญชาตญาณของคุณด้วย บางครั้ง วิธีที่ดีที่สุดในการคิดออกก็คือการเดาอย่างมีการศึกษา ซึ่งจะช่วยคุณประหยัดเวลาได้มากเมื่อเทียบกับการใช้กำลังเดรัจฉาน เมื่อเร็ว ๆ นี้ฉันได้ยินเรื่องราวจากบริษัทที่ต้องทำงานกับ API ที่เป็นกรรมสิทธิ์และมีเอกสารเพียงเล็กน้อยหรือไม่มีเลย พวกเขาพยายามดิ้นรนเพื่อถอดรหัสเพย์โหลดการตอบกลับ API ในรูปแบบที่ไม่รู้จักมาเป็นเวลาหลายวัน จากนั้นมีคนตัดสินใจลองใช้ ?decode=true
ที่ส่วนท้ายของ url และพวกเขามี JSON ที่เหมาะสม บางครั้ง หากคุณโชคดี สิ่งที่คุณต้องทำคือปรับแต่งการตอบสนอง JSON
อีกเหตุผลหนึ่งที่ฉันทำบทช่วยสอนนี้คือ บริษัทบางแห่งใช้เวลานานในการนำคุณลักษณะเฉพาะที่ผู้ใช้ร้องขอมาใช้ แทนที่จะรอให้มีการใช้งาน คุณสามารถควบคุมพลังของ API ส่วนตัวและสร้างมันขึ้นมาเองได้
ดังนั้น ด้วย couchsurfing.com API ใหม่ ฉันจึงเริ่มต้นด้วยแนวทางที่คล้ายกัน และติดตั้งแอป iOS ล่าสุด
ขั้นแรก คุณต้องตั้งค่าพร็อกซีใน LAN ของคุณเพื่อปลอมคำขอ HTTP ที่มาจากแอปไปยัง API โดยดำเนินการโจมตีแบบคนกลาง (MITM)
สำหรับการเชื่อมต่อที่ไม่ได้เข้ารหัส การโจมตีนั้นค่อนข้างง่าย - ไคลเอนต์เชื่อมต่อกับพร็อกซี่ และคุณส่งคำขอที่เข้ามายังเซิร์ฟเวอร์ปลายทางไปมา คุณสามารถแก้ไขเพย์โหลดได้ ถ้าจำเป็น ใน WLAN สาธารณะ ค่อนข้างง่ายที่จะทำการปลอมแปลงโดยแอบอ้างเป็นเราเตอร์ WiFi
สำหรับการเชื่อมต่อที่เข้ารหัส จะมีความแตกต่างเล็กน้อย: คำขอทั้งหมดได้รับการเข้ารหัสจากต้นทางถึงปลายทาง เป็นไปไม่ได้ที่ผู้โจมตีจะถอดรหัสข้อความ เว้นแต่เขาจะเข้าถึงคีย์ส่วนตัว (ซึ่งแน่นอนว่าจะไม่ถูกส่งระหว่างการโต้ตอบเหล่านี้) ต้องบอกว่าแม้ว่าช่องทางการสื่อสาร API จะปลอดภัย แต่ปลายทาง - โดยเฉพาะไคลเอนต์ - ก็ไม่ปลอดภัยขนาดนั้น
ต้องเป็นไปตามเงื่อนไขต่อไปนี้เพื่อให้ SSL ทำงานได้อย่างถูกต้อง:
- ใบรับรองของเซิร์ฟเวอร์ต้องลงนามกับผู้ออกใบรับรองที่เชื่อถือได้ (CA)
- ชื่อทั่วไปของเซิร์ฟเวอร์ในใบรับรองต้องตรงกับชื่อโดเมนของเซิร์ฟเวอร์
เพื่อเอาชนะการเข้ารหัสในการโจมตี MITM พร็อกซีของเราจำเป็นต้องทำหน้าที่เป็น CA (ผู้ออกใบรับรอง) และสร้างใบรับรองได้ทันที ตัวอย่างเช่น หากไคลเอ็นต์พยายามเชื่อมต่อกับ www.google.com พร็อกซีจะสร้างใบรับรองสำหรับ www.google.com และลงนามแบบไดนามิก ตอนนี้ ลูกค้าคิดว่าจริง ๆ แล้วพร็อกซี่คือ www.google.com
ในการใช้พร็อกซีการดมกลิ่นที่ใช้ในการวิศวกรรมย้อนกลับ API ส่วนตัว ฉันจะใช้เครื่องมือที่เรียกว่า mitmproxy คุณสามารถใช้พร็อกซี HTTPS แบบโปร่งใสอื่นๆ ได้ Charles เป็นอีกตัวอย่างหนึ่งที่มี GUI ที่ดี เพื่อให้งานนี้ เราต้องตั้งค่าสิ่งต่อไปนี้:
กำหนดค่าเกตเวย์เริ่มต้นการเชื่อมต่อ WiFi ของโทรศัพท์ของคุณให้เป็นพร็อกซี (เพื่อให้พร็อกซีอยู่ตรงกลางและแพ็กเก็ตทั้งหมดผ่าน) ติดตั้งใบรับรองของพร็อกซีบนโทรศัพท์ (เพื่อให้ไคลเอ็นต์มีพับลิกคีย์ของพร็อกซีในที่เก็บที่เชื่อถือได้)
ตรวจสอบเอกสารของพร็อกซี่ของคุณเกี่ยวกับการติดตั้งใบรับรอง นี่คือคำแนะนำสำหรับ mitmproxy และนี่คือไฟล์ใบรับรอง PEM สำหรับ iOS
ในการตรวจสอบคำขอ HTTP ที่ถูกดักจับ คุณเพียงแค่เปิด mitmproxy และเชื่อมต่อจากโทรศัพท์มือถือของคุณ (พอร์ตเริ่มต้นคือ 8080)
เปิดเว็บไซต์ในเบราว์เซอร์มือถือของคุณ ณ จุดนี้ คุณควรจะสามารถเห็นทราฟฟิกใน mitmproxy ได้
เมื่อคุณแน่ใจว่าทุกอย่างทำงานได้ตามแผนที่วางไว้ ก็ถึงเวลาเริ่มต้นสำรวจ API ส่วนตัวที่คุณเลือก โดยพื้นฐานแล้ว ณ จุดนี้ คุณเพียงแค่เปิดแอป ลองใช้มัน และรับแนวคิดเกี่ยวกับตำแหน่งข้อมูล API และโครงสร้างคำขอ
ไม่มีอัลกอริธึมที่เข้มงวดเกี่ยวกับวิธีการวิศวกรรมย้อนกลับของซอฟต์แวร์ API - ส่วนใหญ่คุณต้องพึ่งพาสัญชาตญาณของคุณและตั้งสมมติฐาน
วิธีการของฉันคือการจำลองการเรียก API และเล่นกับตัวเลือกต่างๆ การเริ่มต้นที่ดีคือการเล่นซ้ำคำขอที่คุณติดอยู่ใน mitmproxy และดูว่าใช้งานได้หรือไม่ (กด 'r' เพื่อเล่นคำขอซ้ำ) ขั้นตอนแรกคือการหาว่าส่วนหัวใดเป็นข้อบังคับ การเล่นส่วนหัวด้วย mitmproxy ค่อนข้างสะดวก: กด 'e' เพื่อเข้าสู่โหมดแก้ไข จากนั้น 'h' เพื่อแก้ไขส่วนหัว ด้วยปุ่มลัดที่พวกเขาใช้ ผู้เสพติดเป็นกลุ่มจะรู้สึกเหมือนอยู่บ้าน คุณยังสามารถใช้ส่วนขยายของเบราว์เซอร์ เช่น Postman เพื่อทดสอบ API ได้ แต่ส่วนขยายเหล่านี้มักจะเพิ่มส่วนหัวที่ไม่จำเป็น ดังนั้นฉันขอแนะนำให้ใช้ mitmproxy หรือ curl
ฉันได้สร้างสคริปต์ที่อ่านไฟล์ดัมพ์ mitmproxy และสร้างสตริง curl - https://gist.github.com/nderkach/bdb31b04fb1e69fa5346
เริ่มต้นด้วยคำขอที่ส่งเมื่อคุณเข้าสู่ระบบ

POST https://hapi.couchsurfing.com/api/v2/sessions ← 200 application/json
สิ่งแรกที่ฉันสังเกตเห็นคือทุกคำขอมีส่วนหัวบังคับ X-CS-Url-Signature
ซึ่งแตกต่างกันไปทุกครั้ง ฉันยังพยายามเล่นคำขออีกครั้งหลังจากผ่านไปครู่หนึ่งเพื่อตรวจสอบว่ามีการประทับเวลาบนเซิร์ฟเวอร์หรือไม่ และไม่มี สิ่งต่อไปที่ต้องทำคือหาวิธีการคำนวณลายเซ็นนี้
ณ จุดนี้ฉันตัดสินใจวิศวกรรมย้อนกลับไบนารีและหาอัลกอริทึม โดยธรรมชาติ เมื่อมีประสบการณ์การพัฒนาสำหรับ iPhone และมี iPhone อยู่แล้ว ฉันจึงตัดสินใจเริ่มต้นด้วย iPhone ipa (ส่งมอบแอปสำหรับ iPhone) กลายเป็นว่าต้องถอดรหัส ฉันต้องการโทรศัพท์ที่เจลเบรคแล้ว หยุด! เวลาค้อน
จากนั้นฉันก็จำได้ว่าพวกเขามีแอพ Android เช่นกัน ฉันลังเลเล็กน้อยที่จะลองใช้วิธีนี้ เนื่องจากฉันไม่รู้อะไรเกี่ยวกับ Android หรือ Java ฉันคิดว่ามันจะเป็นโอกาสดีที่จะเรียนรู้สิ่งใหม่ กลายเป็นว่าง่ายกว่าในการรับซอร์สโค้ดเสมือนที่มนุษย์อ่านได้โดยการถอดรหัสจาวา bytecode มากกว่าโค้ดเครื่อง iphone ที่ปรับให้เหมาะสมที่สุด
Apk (ส่งมอบแอพ Android) นั้นเป็นไฟล์ zip คุณสามารถใช้ตัวแยกไฟล์ zip เพื่อแกะเนื้อหาออก คุณจะพบไฟล์ชื่อ class.dex ซึ่งเป็น bytecode ของ Dalvik Dalvik เป็นเครื่องเสมือนที่ใช้ในการรัน Java bytecode ที่แปลบน Android
ในการถอดรหัสไฟล์ .dex เป็นซอร์สโค้ด .java ฉันใช้เครื่องมือที่เรียกว่า dex2jar ผลลัพธ์ของเครื่องมือนี้คือไฟล์ jar ซึ่งคุณสามารถถอดรหัสได้ด้วยเครื่องมือที่หลากหลาย คุณยังสามารถเปิดโถใน Eclipse หรือ IntelliJ IDEA ได้ และมันจะทำทุกอย่างให้คุณ เครื่องมือเหล่านี้ส่วนใหญ่ให้ผลลัพธ์ที่คล้ายคลึงกัน เราไม่ได้สนใจว่าเราจะคอมไพล์มันกลับมาเพื่อรันมันได้หรือไม่ เราแค่ใช้มันเพื่อวิเคราะห์ซอร์สโค้ด
นี่คือรายการเครื่องมือที่ฉันได้ลอง:
- FernFlower (ปัจจุบันเป็นส่วนหนึ่งของ IntelliJ IDEA)
- CFR
- JD-GUI
- กรากะตัว
- Procyon
CFR และ FernFlower ทำงานได้ดีที่สุดสำหรับฉัน JD-GUI ไม่สามารถถอดรหัสส่วนสำคัญของโค้ดบางส่วนได้และไม่มีประโยชน์ ในขณะที่ส่วนอื่นๆ มีคุณภาพใกล้เคียงกัน โชคดีที่ดูเหมือนว่าโค้ด Java จะไม่สับสน แต่มีเครื่องมืออย่าง ProGuard http://developer.android.com/tools/help/proguard.html ที่จะช่วยคุณถอดรหัสที่สร้างความสับสนให้กับโค้ด
การดีคอมไพล์ Java นั้นไม่ใช่ขอบเขตของบทช่วยสอนด้านวิศวกรรมย้อนกลับนี้จริงๆ - มีบทความมากมายที่เขียนในหัวข้อนี้ ดังนั้น สมมติว่าคุณถอดรหัสสำเร็จและถอดรหัสซอร์สโค้ดที่สร้างความสับสนให้กับโค้ด Java ของคุณ
ฉันได้รวมรหัสที่เกี่ยวข้องทั้งหมดที่ใช้ในการคำนวณ X-CS-Url-Signature ในส่วนสำคัญต่อไปนี้: https://gist.github.com/nderkach/d11540e9af322f1c1c74
ประการแรก ฉันได้ค้นหาการกล่าวถึง X-CS-Url-Signature
ซึ่งพบใน RetrofitHttpClient
การโทรหนึ่งครั้งดูน่าสนใจ - ไปยังโมดูล EncUtils
เมื่อลองค้นดู ฉันก็รู้ว่าพวกเขากำลังใช้ HMAC SHA1 HMAC คือรหัสการตรวจสอบความถูกต้องของข้อความซึ่งใช้ฟังก์ชันการเข้ารหัส (SHA1 ในกรณีนี้) เพื่อคำนวณแฮชของข้อความ ใช้เพื่อรับรองความถูกต้อง (เช่น เพื่อป้องกันไม่ให้ชายที่อยู่ตรงกลางแก้ไขคำขอ) และการรับรองความถูกต้อง
เราต้องการสองสิ่งในการคำนวณ X-CS-Url-Signature
: คีย์ส่วนตัวและข้อความที่เข้ารหัส (อาจเป็นรูปแบบต่างๆ ของเพย์โหลดคำขอ HTTP และ URL)
final String a2 = EncUtils.a(EncUtils.a(a, s)); final ArrayList<Header> list = new ArrayList<Header>(request.getHeaders()); list.add(new Header("X-CS-Url-Signature", a2));
ในโค้ด a
คือข้อความ และ s
คือคีย์ที่ใช้ในการคำนวณส่วนหัว a2
(การเรียกสองครั้งไปยัง EncUtils
เพียงคำนวณ HMAC SHA1 hex Digest)
การค้นหาคีย์ไม่ใช่ปัญหา แต่ถูกเก็บไว้ในข้อความธรรมดาใน ApiModule
และใช้เพื่อเริ่มต้นพารามิเตอร์ตัวที่สองของ RetrofitHttpClient
RetrofitHttpClient a(OkHttpClient okHttpClient) { return new RetrofitHttpClient(okHttpClient, "v3#!R3v44y3ZsJykkb$E@CG#XreXeGCh"); }
ถ้าเราดูที่การเรียก EncUtils
เราจะเห็นว่าสตริงตามตัวอักษรด้านบนนั้นใช้คำต่อคำเป็นคีย์ในการคำนวณ HMAC ยกเว้นในกรณีที่ this.b
ถูกกำหนดไว้ ในกรณีหลัง this.b
จะถูกต่อท้ายด้วยจุด
String s; if (this.b == null) { s = this.a; } else { s = this.a + "." + this.b; }
ตอนนี้เพียงแค่ดูโค้ดก็ไม่ชัดเจนสำหรับฉันว่า this.b
เริ่มต้นที่ไหนและอย่างไร (สิ่งเดียวที่ฉันสามารถค้นพบได้คือมันถูกเรียกในวิธีการที่มีลายเซ็น this.a(String b)
แต่ฉันไม่พบการโทรไปที่ใดก็ได้ในรหัส)
public void a(final String b) { this.b = b; }
ฉันขอแนะนำให้คุณถอดรหัสและค้นหาตัวเอง :)
การค้นหาข้อความค่อนข้างตรงไปตรงมา - ในโค้ดคุณจะเห็นว่าเป็นการต่อกันของพาธ url เช่น /api/v2/sessions
และสตริงที่มี JSON payload (ถ้ามี)
final byte[] b = this.b(request.getUrl()); byte[] a; if (request.getBody() != null && request.getBody() instanceof JsonTypedOutput) { System.out.println("body"); // this.a(x, y) concatenates byte arrays a = this.a(b, ((JsonTypedOutput)request.getBody()).a); } else { a = b; }
เพียงแค่ดูโค้ด ก็ยากที่จะหาอัลกอริทึมที่แน่นอนสำหรับการคำนวณ HMAC ดังนั้นฉันจึงตัดสินใจสร้างแอปขึ้นใหม่ด้วยสัญลักษณ์การดีบัก เพื่อดูว่าแอปทำงานอย่างไร ฉันใช้เครื่องมือที่เรียกว่า apktool https://code.google.com/p/android-apktool/ เพื่อแยกส่วน Dalvik bytecode โดยใช้ smali https://code.google.com/p/smali/ ฉันทำตามคำแนะนำที่ https://code.google.com/p/android-apktool/wiki/SmaliDebugging
หลังจากที่คุณสร้าง apk คุณต้องลงชื่อและติดตั้งบนอุปกรณ์ของคุณ เนื่องจากฉันไม่มีอุปกรณ์ Android ฉันจึงใช้โปรแกรมจำลองที่มาพร้อมกับ Android SDK ด้วยการป้อนด้วยช้อน นี่คือวิธีที่คุณทำ:
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android <path_to_your_built_apk> androiddebugkey jarsigner -verify -verbose -certs <path_to_your_built_apk> zipalign -v 4 <path_to_your_built_apk> <path_to_your_output_signed_apk>
ฉันใช้ตัวจำลอง Android ในตัวซึ่งมาพร้อมกับ sdk และอิมเมจเสมือน Atom x86 ที่เปิดใช้งาน HAXM เพื่อให้แน่ใจว่าทำงานได้อย่างราบรื่น
tools/emulator -avd mydroid -no-boot-anim -cpu-delay 0
นี่คือคำแนะนำที่ดีเกี่ยวกับวิธีการตั้งค่าภาพเสมือน: http://jolicode.com/blog/speed-up-your-android-emulator
ตรวจสอบให้แน่ใจว่าคุณเห็นบรรทัด HAX ทำงานและโปรแกรมจำลองทำงานในโหมด virt ที่รวดเร็ว เมื่อเริ่มต้นโปรแกรมจำลองเพื่อให้แน่ใจว่าคุณเปิดใช้งาน HAXM
จากนั้น ฉันติดตั้ง apk ลงในโปรแกรมจำลองและเรียกใช้แอป ทำตามคำแนะนำ apktool ฉันใช้ประโยชน์จากตัวดีบักระยะไกล IntelliJ IDEA เพื่อเชื่อมต่อกับอีมูเลเตอร์และตั้งค่าเบรกพอยต์บางบรรทัด:
เมื่อใช้แอปนี้สักพัก ฉันก็พบว่าคีย์ส่วนตัวที่ใช้ในการเริ่มต้น RetrofitHttpClient
ใช้สำหรับคำนวณ HMAC ของลายเซ็นคำขอเข้าสู่ระบบ ในการตอบสนองต่อการเข้าสู่ระบบ POST คุณจะได้รับ ID ผู้ใช้และ accessToken ( X-Access-Token
) โทเค็นการเข้าถึงใช้เพื่ออนุญาตคำขอต่อไปนี้ทั้งหมด HMAC สำหรับคำขอโพสต์การเข้าสู่ระบบทั้งหมดถูกสร้างขึ้นในลักษณะเดียวกับคำขอเข้าสู่ระบบ ยกเว้นว่าคีย์ประกอบด้วยการผนวก .<user_id>
ต่อท้ายคีย์ส่วนตัวดั้งเดิม
เมื่อคุณได้รับอนุญาตแล้ว แอปจะส่งคำขอต่อไปนี้:
POST https://hapi.couchsurfing.com/api/v2/users/1003669205/registerDevice ← 200 application/json
เนื่องจากฉันสามารถหักค่าประสบการณ์ได้ คำขอนี้จึงเป็นทางเลือกสำหรับการตรวจสอบสิทธิ์ คะแนนโบนัสถ้าคุณรู้ว่ามันใช้ทำอะไร!
เมื่อตรวจสอบสิทธิ์แล้ว คุณสามารถส่งคำขอเพื่อดึงข้อมูลของคุณ (หรือโปรไฟล์ผู้ใช้ของบุคคลอื่น) ได้ดังนี้:
GET https://hapi.couchsurfing.com/api/v2/users/1003669205 ← 200 application/json
ฉันไม่ได้ลงรายละเอียดมากนัก แต่ฉันสังเกตว่าโปรไฟล์ได้รับการอัปเดตด้วยคำขอ PUT เพื่อความสนุก ฉันพยายามอัปเดตโปรไฟล์อื่นด้วยคำขอเดียวกัน - ไม่ได้รับอนุญาต ดังนั้นจึงเห็นได้ชัดว่ามีการใช้พื้นฐานด้านความปลอดภัย
ฉันเขียนสคริปต์ Python ง่ายๆ เพื่อเข้าสู่ระบบโดยใช้ข้อมูลรับรองของ couchsurfing.com และรับโปรไฟล์ผู้ใช้ของคุณ: https://gist.github.com/nderkach/899281d7e6dd0d497533 นี่คือตัวห่อหุ้ม Python สำหรับ API: https://github.com/nderkach/couchsurfing-python พร้อมแพ็คเกจที่มีอยู่ในที่เก็บ pypi (pip ติดตั้ง couchsurfing)
ขั้นตอนถัดไป
ฉันไม่แน่ใจว่าฉันจะทำอย่างไรกับ API ในครั้งนี้ ไม่อนุญาตให้ใช้โค้ด HTML ในโปรไฟล์ผู้ใช้อีกต่อไป ดังนั้นฉันจะต้องใช้แนวทางอื่นเพื่อแก้ไขปัญหาเดิม ฉันจะพัฒนาและปรับปรุงตัวห่อ python API ต่อไป หากมีความต้องการ และสมมติว่า couchsurfing.com จะไม่ทำให้เกิดปัญหามากเกินไป ฉันไม่ได้สำรวจ API มากเกินไป และเพิ่งทดสอบหาช่องโหว่พื้นฐานบางอย่าง ดูเหมือนปลอดภัยเพียงพอ แต่น่าสนใจที่จะค้นหาว่าคุณสามารถเข้าถึงข้อมูลที่ไม่มีให้บริการผ่านเว็บไซต์ได้หรือไม่ ไม่ว่าจะด้วยวิธีใด ตอนนี้คุณสามารถใช้วิศวกรรมซอฟต์แวร์ย้อนกลับของฉันเพื่อสร้างไคลเอนต์สำรองสำหรับ Windows Phone, Pebble หรือโซฟาอัจฉริยะของคุณ
สรุปคำถาม
มีการสนทนาที่ฉันต้องการเปิด - ทำไมไม่เผยแพร่ API ของคุณและทำให้เป็นสาธารณะ แม้ว่าฉันจะไม่สามารถแฮ็ค API ได้ แต่ก็ยังสามารถขูดเว็บไซต์ได้ การบำรุงรักษาจะช้ากว่าและยากกว่า แต่แน่นอนว่าพวกเขาต้องการให้ผู้บริโภคใช้ API มากกว่าเว็บสแครปเปอร์ ความพร้อมใช้งานของ API จะช่วยให้นักพัฒนาบุคคลที่สามสามารถปรับปรุงผลิตภัณฑ์ของบริษัท และสร้างบริการที่มีมูลค่าเพิ่มได้ เราสามารถโต้แย้งได้ว่าการรักษา API สาธารณะจะมีราคาแพงกว่าการรักษาแบบส่วนตัว แต่ข้อดีของบริการสร้างชุมชนนอกเหนือจากผลิตภัณฑ์ของคุณจะมีค่ามากกว่าค่าใช้จ่ายในการบำรุงรักษา API
เป็นไปได้ไหมที่จะป้องกันการใช้งาน API ส่วนตัวโดยไคลเอนต์บุคคลที่สามโดยสมบูรณ์? ฉันไม่คิดอย่างนั้น การใช้การปักหมุด SSL จะป้องกันการดมกลิ่นคำขอ API โดยใช้เทคนิคพร็อกซีโปร่งใสอย่างง่ายตามที่อธิบายไว้ก่อนหน้านี้ ในท้ายที่สุด แม้ว่าคุณจะสร้างความสับสนให้กับไบนารี แต่แฮ็กเกอร์ที่มีแรงจูงใจด้วยทรัพยากรและเวลาบางส่วนจะสามารถย้อนกลับวิศวกรรมไบนารีของแอปและรับคีย์ส่วนตัว/ใบรับรองได้เสมอ ฉันคิดว่าสมมติฐานที่ว่าปลายทางไคลเอนต์มีความปลอดภัยนั้นผิดโดยเนื้อแท้ ไคลเอนต์ API เป็นจุดอ่อน
โดยการรักษา API ให้เป็นส่วนตัว บริษัทจะส่งข้อความที่ไม่ไว้วางใจไปยังผู้ใช้โดยทั่วไป แน่นอน คุณสามารถพยายามปกป้อง API ส่วนตัวของคุณให้ดียิ่งขึ้นไปอีก อย่างไรก็ตาม คุณไม่ควรใช้การรักษาความปลอดภัยขั้นพื้นฐานสำหรับ API เพื่อป้องกันการใช้งานที่เป็นอันตราย และแทนที่จะเน้นทรัพยากรของคุณในการปรับปรุงซอฟต์แวร์เพื่อมอบประสบการณ์การใช้งานที่ดียิ่งขึ้น?
Couchsurfing ได้โปรดด้วยน้ำตาลอยู่ด้านบน เปิด API