HN เปิดเผย: FlowTracker – ติดตามการไหลของข้อมูลในโปรแกรม Java
(github.com/coekie)- FlowTracker เป็น Java agent ที่ติดตามกระบวนการที่โปรแกรม Java อ่าน จัดการ และเขียนข้อมูล โดยเชื่อมโยงและแสดงให้เห็นว่าเอาต์พุตมาจากอินพุต ไฟล์ เครือข่าย หรือค่าคงที่ในโค้ดใด
- มันสังเกตโปรแกรมที่กำลังทำงานเพื่อแสดงไฟล์และ network I/O และโดยเฉพาะอย่างยิ่งติดตาม ความสัมพันธ์ระหว่างอินพุตกับเอาต์พุต เพื่อช่วยให้เข้าใจว่าเอาต์พุตของโปรแกรม Java หมายถึงอะไรและถูกสร้างขึ้นมาทำไม
- ในเดโม Spring PetClinic สามารถไล่ตามได้ตั้งแต่เฮดเดอร์ของ HTTP response, เทมเพลต Thymeleaf, ค่าฐานข้อมูล ไปจนถึงสคริปต์แทรก SQL ทำให้สำรวจได้หลาย ชั้นของซอฟต์แวร์สแตก
- ภายในระบบใช้การ instrument bytecode ตอน JVM โหลดคลาส และผสาน JDK method hooks, การวิเคราะห์ data flow, การติดตามการเรียกใช้แบบอิง
ThreadLocalและClassOriginTrackerเพื่อคง การแมปแหล่งที่มา ที่เน้นสตริง อักขระ และไบต์ - สถานะปัจจุบันยังใกล้เคียง proof-of-concept มากกว่าจะพร้อมใช้ในโปรดักชัน แม้จะทำงานได้ดีกับบางโปรแกรมตัวอย่าง แต่ไม่เหมาะกับทุกโปรแกรม และมีโอเวอร์เฮดสูงทำให้ความเร็วในการรันลดลงมาก
สิ่งที่ FlowTracker ติดตาม
- FlowTracker เป็น Java agent ที่ติดตามว่าข้อมูลถูกอ่าน ส่งต่อ แปลง และเขียนอย่างไรภายในโปรแกรม Java
- มันไม่ได้หยุดแค่การแสดงไฟล์และ network I/O แต่ยังเชื่อมโยงและแสดงว่าเอาต์พุตของโปรแกรมมาจากอินพุตใด
- จุดประสงค์คือเพื่อทำความเข้าใจว่าเอาต์พุตของโปรแกรม Java หมายถึงอะไร และเหตุใดโปรแกรมจึงเขียนเอาต์พุตนั้น
- โปรเจ็กต์ปัจจุบันเป็น proof-of-concept ที่สำรวจว่าการมองพฤติกรรมของโปรแกรมจากมุมนี้จะให้ข้อมูลเชิงลึกอะไรได้บ้าง
เดโม: ติดตามที่มาของ HTTP response ใน Spring PetClinic
- FlowTracker PetClinic demo ทำให้เห็นในเบราว์เซอร์ว่า Spring PetClinic ประมวลผล HTTP request และสร้างหน้า HTML จากเทมเพลตและข้อมูลฐานข้อมูลอย่างไร
- บนหน้าจอจะแสดง HTTP response ที่ PetClinic ส่งออกทางเครือข่าย และเมื่อคลิกส่วนหนึ่งของ response จะดูได้ในมุมมองด้านล่างว่าส่วนนั้นมาจากที่ใด
- สามารถเลือกอินพุต/ต้นทางหรือเอาต์พุต/ซิงก์ที่ถูกติดตามได้จากต้นไม้ด้านซ้าย หรือจากปุ่มมุมล่างซ้ายบนมือถือ
-
ชั้นการประมวลผล HTTP
- เมื่อคลิก
"HTTP/1.1"หรือเฮดเดอร์ HTTP จะเห็นได้ว่าส่วนนี้ของ response ถูกสร้างโดยคลาส Apache Coyote ในแพ็กเกจorg.apache.coyote - FlowTracker แสดงให้เห็นว่าโค้ดใดสร้างเอาต์พุตใด
- เมื่อคลิก
-
ชั้นเทมเพลต Thymeleaf
- เมื่อคลิกชื่อแท็ก HTML เช่น
"html"หรือ"head"จะเห็นได้ว่าส่วน HTML นั้นมาจากไฟล์layout.html - หลังจากคลิก
layout.htmlแล้วกดปุ่ม+สีด้านล่าง ทุกส่วนที่มาจากไฟล์นั้นจะแสดงด้วยสีเดียวกัน - เมื่อเลื่อนลง จะยืนยันได้ว่าบางส่วนของ response มาจากอีกไฟล์คือ
ownerDetails.html - เมื่อคลิกอักขระ
<หรือ>จะเห็นว่าอักขระนั้นถูกเขียนโดยไลบรารีเทมเพลต Thymeleaf
- เมื่อคลิกชื่อแท็ก HTML เช่น
-
ที่มาของค่าจากฐานข้อมูล
- ตารางในหน้า HTML มีข้อมูลที่มาจากฐานข้อมูล
- เมื่อคลิก
Georgeในตาราง จะติดตามได้ไม่เพียงแค่ว่าค่านั้นมาจากฐานข้อมูล แต่ยังย้อนไปถึง สคริปต์ SQL ที่แทรกค่านั้นลงฐานข้อมูลตั้งแต่แรกด้วย - ที่เดโมนี้ติดตามไปถึงสคริปต์ SQL ได้ เพราะใช้ฐานข้อมูลแบบ in-memory ทำให้เนื้อหาฐานข้อมูลไม่ออกไปนอก JVM
เดโม MySQL และความเป็นอิสระจากเฟรมเวิร์ก
- หากรันเดโม PetClinic เดียวกันด้วยฐานข้อมูล MySQL จะติดตามค่าได้ถึงจุดเชื่อมต่อกับฐานข้อมูล
- ในกรณีนี้สามารถดู SQL query ที่ถูกส่งไปก่อนหน้าเพื่อสร้างค่านั้น และรายละเอียดวิธีที่ไดรเวอร์ MySQL JDBC สื่อสารกับฐานข้อมูลได้
- FlowTracker PetClinic mysql demo ยังแสดงให้เห็นด้วยว่า FlowTracker ดักจับเนื้อหาที่ถอดรหัสแล้วซึ่งถูกส่งผ่านการเชื่อมต่อ SSL ของฐานข้อมูล
- Spring PetClinic เป็นเพียงตัวอย่าง และ FlowTracker ไม่ได้พึ่งพาเฟรมเวิร์กหรือไลบรารีเฉพาะใด
- javac demo แสดงให้เห็นว่า FlowTracker ช่วยทำความเข้าใจรูปแบบไฟล์ class และ bytecode ภายในที่ Java compiler สร้างขึ้นได้อย่างไร
วิธีใช้งานและข้อควรระวัง
- ปัจจุบัน FlowTracker ยังใกล้เคียงกับ proof-of-concept มากกว่าสถานะ พร้อมใช้ในโปรดักชัน
- แม้จะทำงานได้ดีกับโปรแกรมตัวอย่างหลายตัว แต่ไม่รับประกันว่าจะทำงานได้ดีกับทุกโปรแกรม
- มันเพิ่มโอเวอร์เฮดจำนวนมาก ทำให้การรันโปรแกรมช้าลงอย่างมาก
- ขั้นตอนการใช้งาน:
- ดาวน์โหลด agent jar
flowtracker-*.jarจาก Github releases pages - เพิ่ม
-javaagent:path/to/flowtracker.jarในบรรทัดคำสั่ง Java - เพิ่มผลลัพธ์ของ
java -jar flowtracker.jar jvmoptsลงในบรรทัดคำสั่งด้วย เพื่อปิด JVM optimization บางอย่างที่รบกวน FlowTracker - โดยค่าเริ่มต้น FlowTracker จะเริ่มเว็บเซิร์ฟเวอร์ที่พอร์ต 8011 ดังนั้นให้เปิด
http://localhost:8011/ในเบราว์เซอร์
- ดาวน์โหลด agent jar
- ตัวเลือกการตั้งค่าที่ละเอียดกว่านี้มีอยู่ใน
USAGE.md
การทำงานภายใน: การ instrument bytecode และโมเดล Tracker
- FlowTracker เป็น agent สำหรับ instrument ที่ฉีดโค้ดเข้าไปในไฟล์คลาสหรือ bytecode ตอนที่ JVM โหลดคลาส
- โค้ดที่ถูกฉีดจะรักษาการแมประหว่างข้อมูลในหน่วยความจำกับแหล่งที่มาไว้ระหว่างที่โปรแกรมอ่าน ส่งต่อ และเขียนข้อมูล
- จุดเน้นของการติดตามอยู่ที่ ข้อมูลข้อความและไบนารี เช่น
String,char,byte[]ไม่ได้มุ่งเน้นที่ตัวเลข ข้อมูลแบบมีโครงสร้าง หรือข้อมูลที่คำนวณขึ้นมา - วิธีที่ใช้:
- แทนที่การเรียก JDK method บางส่วนด้วยการเรียกเมธอดเวอร์ชันของ FlowTracker
- ฉีดโค้ดเข้าไปยังตำแหน่งสำคัญใน JDK เพื่อติดตามอินพุตและเอาต์พุต
- ทำ data flow analysis และ instrument เชิงลึกมากขึ้นเพื่อติดตามตัวแปรโลคัลและค่าบนสแตกภายในเมธอด
- เพิ่มโค้ดก่อนและหลังการเรียกเมธอด รวมถึงที่ต้นและท้ายของเมธอดที่ถูกเรียก เพื่อใช้
ThreadLocalติดตามอาร์กิวเมนต์และค่าที่ส่งกลับ
-
โมเดลข้อมูลของ Tracker
Tracker: เก็บเนื้อหาและข้อมูลแหล่งที่มาของอ็อบเจ็กต์ที่ถูกติดตามcontent: ข้อมูล เช่น ไบต์ทั้งหมดที่ผ่านInputStreamหรือOutputStreamsource: เชื่อมช่วงที่เฉพาะเจาะจงของเนื้อหาเข้ากับช่วงที่เฉพาะเจาะจงของ tracker อื่นTrackerRepository: เก็บMap<Object, Tracker>แบบโกลบอลขนาดใหญ่ที่เชื่อมอ็อบเจ็กต์ที่สนใจกับTrackerของมันTrackerPoint: ชี้ไปยังตำแหน่งหนึ่งภายใน tracker และใช้แทนค่า primitive เดี่ยว เช่น ต้นทางของbyteหนึ่งตัว
การทำ instrumentation ขั้นพื้นฐาน: JDK hook และ ASM
- FlowTracker แทรกการเรียกเมธอด hook เมื่อมีการเรียกเมธอด JDK บางตัว เพื่อให้
Trackerอัปเดตอยู่เสมอ - ตัวอย่างที่ง่ายที่สุดคือ
System.arraycopy- แทนที่การเรียก
java.lang.System.arraycopyด้วยการเรียกcom.coekie.flowtracker.hook.SystemHook.arraycopy SystemHookจะเรียกarraycopyจริงก่อน จากนั้นดึง tracker ของอาร์เรย์ต้นทางและปลายทางจากTrackerRepositoryแล้วอัปเดตให้ tracker ของปลายทางชี้ไปยังต้นทาง
- แทนที่การเรียก
- การทำ instrumentation ลักษณะนี้ใช้ ไลบรารีจัดการไบต์โค้ด ASM
- hook ส่วนใหญ่ไม่ได้ถูกเพิ่มที่ฝั่งผู้เรียก แต่เพิ่มภายในเมธอด JDK ฝั่งที่ถูกเรียก
- ตัวอย่างเช่น เพิ่มการเรียก
FileInputStreamHook.afterReadByteArrayไว้ท้ายFileInputStream.read(byte[]) - instrumentation นี้ถูกทำด้วยไมโครเฟรมเวิร์กภายในแบบอิง annotation ที่ใช้
AdviceAdapterของ ASM
- ตัวอย่างเช่น เพิ่มการเรียก
- FlowTracker เพิ่ม hook ให้กับคลาสฝั่ง I/O ของ JDK เช่น
java.io.FileInputStream,java.io.FileOutputStream,sun.nio.ch.FileChannelImpl,sun.nio.ch.IOUtil,sun.nio.ch.NioSocketImpl - โค้ดที่เกี่ยวข้อง:
การติดตามค่า primitive และการวิเคราะห์การไหลของข้อมูลภายในเมธอด
- ค่า primitive เช่น
byteไม่มี identity แบบอ็อบเจ็กต์ จึงติดตามอย่างปลอดภัยด้วยคีย์MapของTrackerRepositoryไม่ได้ - FlowTracker เขียนโค้ดใหม่เพื่อเก็บที่มาของค่า primitive แยกไว้ในตัวแปรภายในเมธอด
- ตัวอย่างเช่น หลัง
byte b = x[1]จะใช้ArrayHook.getElementTracker(x, 1)เพื่อดึง tracker ของbและเมื่อy[2] = bก็ใช้ArrayHook.setElementTracker(y, 2, bTracker)เพื่อบันทึกที่มาลงในอาร์เรย์ปลายทาง - เพื่อทำสิ่งนี้ FlowTracker ทำ symbolic interpretation บนความสามารถด้านการวิเคราะห์ของ ASM
- ที่แต่ละจุดของเมธอด มันจะจำลองว่าค่าในตัวแปรภายในและสแตกมาจากที่ใดและไหลไปที่ใด
- โค้ดที่เกี่ยวข้อง:
- FlowValue และ ArrayLoadValue
- MergedValue: จัดการกรณีที่ค่าหนึ่งอาจมาจากหลายตำแหน่งเนื่องจาก control flow เช่น if หรือ loop
- FlowInterpreter: ส่วนขยายของ ASM
Interpreterสำหรับตีความคำสั่งไบต์โค้ดและสร้างFlowValueที่เหมาะสม - Store และ ArrayStore
- FlowTransformer: ขับเคลื่อนกระบวนการวิเคราะห์และ instrumentation ทั้งหมด
- ไม่ได้ติดตามค่า primitive ทุกชนิด โดยเน้นที่
byteและcharและรองรับintกับlongในขอบเขตที่จำกัดกว่า
การไหลของข้อมูลข้ามการเรียกเมธอด
- การวิเคราะห์ภายในเมธอดเพียงอย่างเดียวไม่เพียงพอสำหรับกรณีที่ค่า primitive ไหลผ่านอาร์กิวเมนต์และค่าที่คืนกลับของเมธอดอื่น
- FlowTracker เก็บ
PointTrackerของอาร์กิวเมนต์และค่าที่คืนกลับไว้ในInvocationแล้วใส่มันลงในThreadLocalทันทีก่อนเรียกเมธอด - ที่จุดเริ่มต้นของเมธอดที่ถูกเรียก จะใช้
Invocation.start(...)เพื่อดึงข้อมูลจากThreadLocalออกมาและใช้ที่มาของอาร์กิวเมนต์แบบ primitive ได้ - ด้วยวิธีนี้ แม้ในกรณีที่ส่งค่า primitive เข้าเมธอดอย่าง
out.write(b)ก็ยังสืบทอด tracker ของvalueภายในwrite(byte value)ต่อได้ - โค้ดที่เกี่ยวข้อง:
จัดการตัวโค้ดเองเป็นแหล่งที่มาของข้อมูล
- แหล่งที่มาหลักที่ FlowTracker ติดตามคือค่าที่มาจาก I/O และจากตัวโค้ดเอง
- ค่าที่มาจากโค้ดรวมถึงค่าคงที่แบบ primitive และ
Stringเช่น'a',"abc" - สำหรับค่าคงที่เหล่านี้ จะสร้าง
ClassOriginTrackerแยกตามแต่ละคลาส และเก็บเนื้อหาที่แสดงคลาสกับการอ้างอิงค่าคงที่ในรูปข้อความ - เมื่อมีการอ้างอิงค่าคงที่ tracker ของค่านั้นจะชี้ไปยังตำแหน่งภายในข้อความแทนค่านี้
- โมเดลนี้ปฏิบัติต่อค่าคงที่ราวกับว่าถูกอ่านมาจากข้อความแทนตัวโค้ด จึงคล้ายกับโมเดลการติดตาม I/O
- เพื่อประสิทธิภาพ จึงใช้ ConstantDynamic (JEP 309) เพื่อไม่ให้มีการเรียกเมธอด
constantPointทุกครั้งที่มีการรันเมธอด - การติดตั้งใช้งานที่เกี่ยวข้อง:
การจัดการ String literal และข้อจำกัด
- สำหรับ String literal จะสร้างสำเนา
Stringใหม่ แล้วเชื่อมbyte[]ภายในString.valueเข้ากับClassOriginTracker - คำสั่งอย่าง
String s = "abc";จะถูกเขียนใหม่เป็นรูปString s = StringHook.constantString("abc", 1234, 81); - วิธีนี้ทำให้การรับประกันเรื่อง String interning ที่ JVM ปกติมอบให้เสียไป
- โดยปกติการปรากฏทั้งหมดของ String ค่าคงที่เดียวกันต้องอ้างอิงอินสแตนซ์เดียวกัน
- หลังทำ instrumentation แล้ว โค้ดที่พึ่งพาการรับประกันนี้อาจพังได้
- FlowTracker มีมาตรการบางอย่างเพื่อลดปัญหานี้
- ใช้ ConstantDynamic เพื่อให้ String literal เดียวกันในบรรทัดเดียวกัน แม้จะถูกรันหลายครั้ง ก็ยังคืนค่าเป็นอินสแตนซ์เดิมทุกครั้ง
- เขียนนิพจน์
stringA == stringBบางส่วนใหม่เป็นObjects.equals(stringA, stringB)เพื่อให้ในบางมุมมองดูเสมือนเป็นอินสแตนซ์เดียวกัน - ปิดการติดตาม String literal ในบางแพ็กเกจ เช่น
java.lang.* - พฤติกรรมนี้ตั้งค่าได้ด้วย
breakStringInterningในUSAGE.md
- การติดตั้งใช้งานที่เกี่ยวข้อง:
fallback สำหรับค่าที่ไม่ได้ถูกติดตาม
- FlowTracker ไม่ได้ติดตามค่าทุกค่าในโปรแกรม
- เหตุผลคือความกังวลด้านประสิทธิภาพ ส่วนที่ยังไม่ได้ติดตั้งใช้งาน ค่าที่มีความเกี่ยวข้องต่ำ และการแทนค่าที่เกิดจากการผสมกันของหลายแหล่งที่มาต้องใช้โมเดลข้อมูลที่ซับซ้อนกว่า
- เมื่อค่าที่เดิมไม่ได้ถูกติดตามไปถึงจุดที่จำเป็นต้องเริ่มติดตาม ระบบจะเชื่อมค่านั้นเข้ากับ
ClassOriginTrackerคล้ายกับค่าคงที่ และแสดงตำแหน่งนั้นเป็น"<?>" - ตัวอย่างเช่น ความยาวของอาร์เรย์ไม่ได้ถูกติดตาม ดังนั้นเมื่อมีการเรียก
write(array.length)จะมีการส่งPointTrackerที่ชี้ไปยังตำแหน่งโค้ดของจุดเรียกwriteเข้าไปในInvocation - ผลลัพธ์คือ แม้ในเอาต์พุตแบบไบนารีจะมองไม่เห็นแหล่งที่มาเดิม แต่บางครั้งก็ยังตีความความหมายของค่าได้อย่างรวดเร็วผ่านสตริงที่ถูกติดตามรอบข้างและตำแหน่งในโค้ด
หัวข้อการติดตั้งใช้งานที่ยังเจาะลึกได้อีก
- MergedValue จัดการการติดตามค่าที่ผ่าน branch และ loop ซึ่งถือเป็นส่วนที่ยากที่สุดของการวิเคราะห์การไหลของข้อมูล
- String concatenation ถูกจัดการโดยเพิ่ม hook เข้าไปใน
MethodHandleที่StringConcatFactoryส่งคืนผ่าน indification (JEP 280) - การค้นหาซอร์สโค้ด การดีคอมไพล์ด้วย Vineflower และการเชื่อมโยงไบต์โค้ดกับบรรทัดของซอร์ส ก็รวมอยู่ในการติดตั้งใช้งานด้วย
- การออกแบบ ClassLoader มุ่งหลีกเลี่ยง dependency ของ bootclasspath และการชนกันกับแอปพลิเคชัน พร้อมทั้งรักษาวงจรการพัฒนาให้รวดเร็วโดยไม่ใช้ shading และ nested jar
- การติดตามค่า primitive ที่ถูกเก็บไว้ใน field ก็รวมอยู่ในการติดตั้งใช้งานด้วย
- ฝั่งฟรอนต์เอนด์ประกอบด้วยเว็บเซิร์ฟเวอร์บน Jetty และ JAX-RS และเว็บ UI บน Svelte
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
สำหรับการ instrument ผมใช้ fork ของคอมไพเลอร์ Clojure อย่างเป็นทางการแทน instrumentation agent และอาศัยคุณสมบัติของ Clojure ที่สลับคอมไพเลอร์ระหว่างพัฒนาได้ง่าย เพื่อแทรก bytecode เพิ่มเข้าไป
สิ่งที่น่าสนใจเกี่ยวกับบันทึกการรันโปรแกรม Clojure คือค่าหลัก ๆ ส่วนใหญ่เป็น immutable ดังนั้นแค่เก็บ pointer ไว้ก็สามารถทำ snapshot ได้
เพราะเดโมในบทความต้นฉบับเป็นการสำรวจเว็บแอป เลยขอฝากเดโมการดีบักเว็บแอปด้วย FlowStorm ไว้สำหรับผู้ที่สนใจ https://www.youtube.com/watch?v=h8AFpZkAwPo
ชอบที่เครื่องมือใน ระบบนิเวศ Java/JVM ยอดเยี่ยมมาก ครั้งก่อนที่ผมทึ่งแบบนี้คือตอนเห็น jitwatch https://github.com/AdoptOpenJDK/jitwatch
FlowTracker ทำให้นึกถึง taint analysis อยู่บ้าง คือการติดตามว่าอินพุตจากผู้ใช้ที่ยังไม่ผ่านการตรวจสอบหรือค่าลับไหลผ่านโปรแกรมอย่างไร เพื่อไม่ให้รั่วไหลหรือถูกใช้โดยไม่ตรวจสอบ
คีย์เวิร์ดสำหรับค้นหาคือ “dynamic taint tracking/analysis”
https://github.com/gmu-swe/phosphor
https://github.com/soot-oss/SootUp
https://github.com/feliam/klee-taint
จินตนาการได้เลยว่าในอนาคตเครื่องมือแบบนี้จะกลายเป็น ด่านป้องกันแรก เวลาไล่ตามบั๊ก
ระหว่างพัฒนา FlowTracker งานจำนวนมากเกิดจากการทำให้การติดตามของโปรแกรมตัวอย่างเฉพาะบางตัวทำงานได้
ผมรู้ผลลัพธ์เป้าหมายอยู่แล้ว แต่คาดเดายากว่าตัวอย่างใดตัวอย่างหนึ่งจะต้องรองรับกลไกระดับต่ำแบบไหนถึงจะทำงานได้ และมักขึ้นอยู่กับรายละเอียด implementation ภายในของ JDK หรือไลบรารีที่ข้อมูลไหลผ่าน
แต่กรณีที่องค์ประกอบ HTML เชื่อมโยงไปยังสคริปต์ SQL ที่ใส่ข้อมูลนั้นลง DB ไม่ได้เป็นแบบนั้น
มันไม่ได้เกิดจากการคาดหวังหรือตั้งใจทำไว้ แต่เกิดขึ้นเองแบบนั้นเลย ผมจึงค่อนข้างประหลาดใจเหมือนกัน และทำให้ตั้งตารอดูว่าแนวทางนี้จะทำอะไรได้อีก
ถ้ามีวิธีติดตามว่าข้อมูลเป็นข้อมูลชั่วคราวหรือเป็นข้อมูลที่ควรถูกเขียนบันทึกกลับไป ก็คงดี
ยิ่งเราระบุข้อจำกัดแบบนี้ไว้ด้านหน้าได้มากเท่าไรก็ยิ่งดี
ใน Smalltalk ทุกอย่างเป็น object และ message จึงสามารถไล่ย้อนกลับและโต้ตอบได้
แม้จะไม่ได้หาเวลาขยายต่อ แต่ผมคิดว่าเครื่องมือพัฒนาเว็บจะได้ประโยชน์มากจาก การติดตามการระบุที่มาทั้งสแตก แบบนี้
อย่างไรก็ตาม การผสานโซลูชันแบบนี้เข้ากับเฟรมเวิร์กที่มีอยู่แล้วรู้สึกว่าเป็นความท้าทายใหญ่
[1] HTML Source Maps - https://github.com/connorjclark/html-source-maps https://docs.google.com/document/d/19XYWiPL9h9vA6QcOrGV9Nfkr...
https://www.youtube.com/watch?v=TWAMr72VaaU&t=164s และ https://witheve.com/
ถ้าขยายสิ่งที่ FlowTracker ทำอยู่ ก็สามารถหา SQL หรือ ช่องโหว่ injection แบบอื่น ๆ ได้เช่นกัน ดังนั้นเครื่องมือที่คุณนึกถึงอาจใช้แนวทางคล้ายกันก็เป็นไปได้
หรือคำถามอย่าง “สตริงนี้เห็นอะไรมาบ้างตั้งแต่ตอนถูกสร้างจนมาถึงหน้าจอของฉัน”
นี่ดูเหมือนเป็นอีกก้าวหนึ่งไปในทิศทางนั้น
ตอนนี้ต้องพักไว้ชั่วคราว แต่ก็ตั้งตารอที่จะทำให้มันรันได้แล้วลองกดดูโน่นนี่