Java Observability Toolkit (JOT) เป็นแพลตฟอร์มสำหรับทำให้แอปพลิเคชัน Java ใดๆ สามารถมองเห็นได้ โดยไม่ต้องเขียนโค้ดใดๆ หรือแม้แต่คอมไพล์ใหม่ แพลตฟอร์มประกอบด้วย...
คุณสามารถสร้าง JOT ได้อย่างรวดเร็วและง่ายดายโดยไม่ต้องเขียนโค้ดใดๆ JOT สามารถสร้างอะไรก็ได้ในแอปพลิเคชัน Java ที่ทำงานอยู่ซึ่งสามารถสังเกตได้ นี่คือตัวอย่างบางส่วนของสิ่งที่คุณอาจใช้เพื่อ... แต่ข้อจำกัดเพียงอย่างเดียวคือความคิดสร้างสรรค์ของคุณ
คุณติดอยู่กับการแก้ไขปัญหาการผลิตและคุณมีบันทึกหรือความสามารถในการแก้ไขข้อบกพร่องไม่เพียงพอ ด้วยกฎ JOT ง่ายๆ คุณสามารถรับข้อมูลที่คุณต้องการได้อย่างรวดเร็วและง่ายดาย
คุณต้องการตรวจสอบบางสิ่งที่เข้าถึงได้เฉพาะภายในแอปเท่านั้น และคุณไม่มีวิธีเปิดเผยสิ่งนี้กับเครื่องมือของคุณ
คุณต้องการป้องกันการใช้วิธีการอันทรงพลังในทางที่ผิดโดยผู้โจมตี แต่พวกเขาอยู่ในไลบรารีที่คุณไม่ได้ควบคุม
เป้าหมายของ JOT คือการมอบพลังเครื่องมือสูงสุดโดยไม่กระทบต่อความเรียบง่าย
แจ้งให้เราทราบถึงสิ่งดีๆ ที่คุณทำกับ JOT! และพิจารณาสนับสนุนพวกเขากลับเข้าสู่โปรเจ็กต์เพื่อให้ผู้อื่นได้แบ่งปันความสุดยอดของคุณ วิธีที่ง่ายที่สุดในการสนับสนุนคือการสร้างคำขอดึง หากคุณกำลังแบ่งปัน JOT ให้เพิ่มมันลงในไดเร็กทอรี "สนับสนุน" ของโปรเจ็กต์... และโปรดใส่ความคิดเห็นที่มีรายละเอียดว่ามีวัตถุประสงค์เพื่อใช้ทำอะไร
กำหนดเซ็นเซอร์และรายงานในรูปแบบ yaml และบันทึกเป็นไฟล์ .jot เซ็นเซอร์จะกำหนดข้อมูลที่จะบันทึกและ "รายงาน" จะบอก JOT ถึงวิธีการติดตามข้อมูลเมื่อเวลาผ่านไป
sensors:
- name: "get-ciphers"
description: "Identifies encryption ciphers"
methods:
- "javax.crypto.Cipher.getInstance"
captures:
- "#P0"
reports:
- name: "Encryption Usage"
type: "list"
cols: "get-ciphers"
โดยพื้นฐานแล้ว สิ่งที่คุณต้องทำคือเพิ่ม JOT ให้กับ JVM
จากนั้นคุณเพียงแค่ใช้แอปพลิเคชันของคุณตามปกติและให้ JOT รวบรวมข้อมูลให้คุณ JOT จะสร้างตารางที่ดีเพื่อบันทึกตำแหน่งที่ใช้การเข้ารหัสและอัลกอริทึมที่ระบุ
Encryption Algorithms get-ciphers
------------------------------------------------------------ ----------------------
com.acme.ticketbook.Ticket.encrypt(Ticket.java:125) DES
org.apache.jsp.accessA_jsp._jspService(accessA_jsp.java:212) AES
org.apache.jsp.accessA_jsp._jspService(accessA_jsp.java:213) PBEWithMD5AndTripleDES
org.apache.jsp.accessB_jsp._jspService(accessB_jsp.java:212) DES
org.apache.jsp.accessC_jsp._jspService(accessC_jsp.java:212) DES/CBC/PKCS5Padding
คุณอาจพบว่าการใช้ตัวแปรสภาพแวดล้อม JAVA_TOOL_OPTIONS มีประโยชน์ เช่น "export JAVA_TOOL_OPTIONS="-javaagent:jot.jar=ciphers.jot" ดังนั้น ไม่ว่าในที่สุด Java จะเปิดตัวอย่างไรก็ตาม มันก็จะใช้ JOT
หากคุณต้องการใช้ JOT หลายไฟล์พร้อมกัน คุณสามารถรวมไฟล์ทั้งหมดไว้ในไฟล์ .jot ขนาดใหญ่ไฟล์เดียว หรือคุณสามารถใส่ไฟล์ .jot หลายไฟล์ในไดเร็กทอรีและใช้ "-javaagent:jot.jar=directory"
สุดท้ายนี้ JOT ทุกตัวสามารถมี "การจับภาพ" ได้หลายรายการ การบันทึกเป็นวิธีระบุข้อมูลที่คุณต้องการรวบรวมจากวิธีการที่คุณระบุไว้ใน JOT การจับอย่างง่ายมีดังนี้: #P0 - พารามิเตอร์แรก #P1 - พารามิเตอร์ตัวที่สอง #ARGS - พารามิเตอร์ทั้งหมดที่ต่อกันในสตริง #OBJ - อ็อบเจ็กต์ที่เรียกใช้เมธอดบน #RET - การส่งคืนจากเมธอด
จริงๆ แล้วการจับภาพคือนิพจน์ Spring Expression Language (SpEL) ดังนั้นคุณจึงสามารถเรียกใช้เมธอดบนออบเจ็กต์พื้นฐานเหล่านั้น เปรียบเทียบเนื้อหา และดำเนินการได้ ซึ่งจะช่วยให้คุณสังเกตสิ่งที่คุณต้องการได้อย่างชัดเจน ดูรายละเอียดทั้งหมดเกี่ยวกับการเขียนเซ็นเซอร์ของคุณเองด้านล่าง
JOT ใช้ FluentLogger ซึ่งรับการกำหนดค่าจาก java.util.logging
และสามารถกำหนดค่าโดย JVM ด้วย -Djava.util.logging.config.file
การกำหนดค่าตัวอย่างนี้จะบันทึก JOT ไปที่ stdout เช่นเดียวกับ /tmp/jot.log
handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1$tF %1$tT %4$-7s [%2$s] - %5$s %n
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=/tmp/jot.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append=true
โดยใช้:
java -javaagent:jot.jar=ciphers.jot -Djava.util.logging.config.file=/root/jul.properties
เซ็นเซอร์คือวิธีที่คุณกำหนดข้อมูลที่คุณต้องการรวบรวม คุณยังสามารถใช้เซ็นเซอร์เพื่อดำเนินการจำกัดภายในแอปพลิเคชันได้
# The name of this sensor, which can be referenced by reports
- name: "get-ciphers"
# Use this to describe what this sensor does. Try to provide enough
# detail so that anyone would understand what it's about.
description: "What does sensor do?"
# A list of methods to gather data from. To avoid potential performance issues,
# avoid putting sensors in methods that are extremely frequently used,
# like StringBuffer.append() or File.<init>.
methods:
- "a.b.c.Class.method"
- "d.e.f.Class.method"
# Scopes allow you to limit when a sensor will fire.
# A sensor will fire if it is invoked while "inside" one of the scopes. That is,
# when any of these methods is on the stack.
# You can define negative scopes using !scope, so that this sensor will only fire outside the scope
# For static methods you need to prefix the method with "static"
scopes:
- "a.b.c.Class.method" # matches only if inside method
- "!a.b.c.Class.method" # matches only if NOT inside method
- "static a.b.c.Class.method" # matches if inside static method
# Excludes allow you to prevent data from being gathered from any
# classes that starts with any of these patterns or are "isAssignableFrom" these classes
# FIXME: currently you must put .all after each classname
excludes:
- "javax.el.MapELResolver.all"
- "org.foo.package.all"
# Captures are the workhorse of JOT and are written in Spring Expression Language (SpEL)
# You may reference data from the method currently running.
# Options are OBJ, P1..P10, ARGS, RET, STACK. These objects are whatever type they happen
# to be, and you can invoke any existing methods on those objects. Note that STACK is a StackFrame[]
# See https://blog.abelotech.com/posts/useful-things-spring-expression-language-spel/
captures:
- "#RET?.toUpperCase()" # call toUpperCase if #RET is not null (note ?. operator)
- """+#P0+":"+#RET" # for methods that take a name and return a value
- "#OBJ.getCanonicalPath() + " " + #OBJ.exists() ? [EXISTS] : [DOES NOT EXIST]" # use ternary operator
- """+#P0+":"+(#RET ? "Y" : "N")" # for methods that return boolean
# Matchers allow you to filter the data that was captured with a set of regular expressions.
# If there are no matchers then all captures will report data.
# Positive matchers only fire if the data matches the pattern. You'll get a result if any positive matchers match.
# Negative matchers (starting with !) only fire if the data does not match the pattern. You'll get a result if no negative matchers match.
# If you mix positive and negative, you'll get a result if any positive captures match and no negative matchers match.
matchers:
- "^\w*$" # matches anything with word characters start to finish
- "!^\[foo" # matches anything that doesn't start with foo
- "!null" # hide empty results from output
# Exceptions are a way to change the behavior of an application.
# If the sensor fires (capture occurs and matchers fire) then JOT will
# throw a SensorException.
# The message should be appropriate for end user, JOT will log all the relevant details.
# Note that generally you don't want to use #RET in your capture if you're throwing an exception,
# because it will throw at the end of the method, which is probably too late.
exception: "Message"
# Debug mode will generate extra logging for this rule only
debug: "false"
รายงานช่วยให้คุณกำหนดวิธีที่ JOT จะรวบรวมข้อมูลเมื่อเวลาผ่านไป และจะจัดรูปแบบข้อมูลให้คุณอย่างไร
# Title of this report that will be displayed above the results
- name: "example"
# Type of reports include
# 1. list
# ROWS: caller method
# COLS: one column named after the sensor defined in "cols"
# DATA: values from the sensor named in "cols"
# 2. compare
# ROWS:
# COLS: uses the "cols" sensor values as column headers
# DATA: values from the sensor named in "cols"
# 3. table
# ROWS:
# COLS: uses rule names for cols[0-n] as column headers - parses data values
# DATA: values from the sensor named in "cols"
# 4. series - table but each row starts with a timestamp (currently includes callers col too)
# ROWS:
# COLS: uses rule names for cols[0-n] as column headers - parses data values
# DATA: values from the sensor named in "cols"
type: "table"
# Rows indicates a sensor to be used to populate row headers
rows: "get-routes"
# Cols indicates a sensor (or list of sensors) to be used to populate column headers
cols: "get-users"
# Data indicates how the content of data cells should be populated. Can be a fixed string or a rule name.
data: "X"
ควรง่ายเหมือนกับการโคลน repo นี้และสร้างด้วย maven
$ git clone https://github.com/planetlevel/jot.git
$ cd jot
$ mvn install
จากนั้นคุณสามารถใช้ jot-xxjar ในไดเร็กทอรีเป้าหมาย
ยินดีบริจาค ดูตัวติดตามข้อบกพร่องเพื่อค้นหาปัญหาที่จะดำเนินการหากคุณต้องการทำให้ JOT ดีขึ้น
- Solve problem of sensors inside JOT scope
1) don't instrument JOT classes -- anything using shading
2) use global scope to check anywhere you're inside a sensor call
- Create separate JOT log file instead of using java.util.logging
- New rules
1) which routes are non-idempotent?
- Sensors
# future features - maybe think about reporting?
# enabled: "false"
# sample: "1000" # report every 1000 times? time frequency?
# counter: "?" # report 10 mins?
# scope: include a capture and regex to say whether to start scope (if service.P0.getParameter=foobar)
# exec: run this code. before? after? during?
- Reports
# possible additions to cols -- caller, stack[n], trace#
- Query Language
# investigate using query language instead of yaml jots.
# Perhaps two types of "queries" -- one to create sensors, another to pull reports.
# SELECT #P0.toUpperCase()
FROM java.lang.Runtime.getRuntime.exec
WITHIN javax.servlet.Servlet.service
WHERE pattern
# SELECT [capture, capture]
FROM [method, method]
EXCLUDE [class, class]
WITHIN [scope, scope]
WHERE [pattern, pattern]
THROWS [msg]
# SELECT #P0 FROM javax.crypto.Cipher.getInstance
# SELECT #P0 FROM javax.crypto.Cipher.getInstance
WHERE "DES|DESEDE"
THROWS "Weak encryption algorithm detected"