report-log — Log Field Inventory
บทนี้ (branch: master) รวบรวม ทุก field ที่พบในรูปแบบ request-log ของ vtrc-api ตามที่ commit ไว้ใน repo นี้ และชนิด PII ที่รั่ว — ค่าจริงถูก redact ในเอกสารนี้
1. Line envelope (นอก JSON)
| Field | ตัวอย่างรูปแบบ | Citation |
|---|---|---|
| timestamp | 4/20/2023, 12:00:05 AM (locale th-TH ตาม TIME_ZONE ของ API) | request_2023-04-20.log:1; writer wlog.js:19 |
| level | [INFO] | request_2023-04-20.log:1 |
ในชุดไฟล์ที่ commit ไว้ การ grep [ERROR] / [WARNING] ใน report-log/ ไม่พบในระดับ request files ที่ตรวจ — response errors อยู่ใน response_*.log ของ API host ซึ่งไม่มีใน repo นี้
2. JSON top-level (ทุกบรรทัด request)
| Field | Always? | ความหมาย | Producer citation |
|---|---|---|---|
query | ใช่ | ชื่อ operation หรือ full GraphQL string ที่ compress whitespace | logging.js:66 |
headers | ใช่ | สำเนา HTTP headers ของ request | logging.js:68 |
from | ใช่ | { appId, userId } จาก Apollo context | logging.js:69 |
variables | บางบรรทัด | GraphQL variables object เมื่อ client ส่งแยกจาก query text | logging.js:67 |
3. from object
| Field | Type | หมายเหตุ | Citation |
|---|---|---|---|
appId | UUID | map จาก device registry ของ vtrc-api | request_2023-04-20.log:1 |
userId | UUID หรือ null | null เมื่อยังไม่ authenticate | ตัวอย่าง null ใน request_2023-02-17.log (บรรทัดที่มี userId null) |
4. headers keys ที่พบใน sample
จากการสุ่มอ่านไฟล์วันที่ 2023-02-17 / 03-20 / 04-20 พบ key ต่อไปนี้ (ไม่ครบทุกบรรทัดทุกวัน แต่เป็นชุดที่ปรากฏจริง):
accept, accept-encoding, accept-language, apikey, authorization, cache-control, connection, content-length, content-type, cookie, dnt, from, host, if-none-match, origin, postman-token, pragma, purpose, referer, save-data, sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform, sec-fetch-dest, sec-fetch-mode, sec-fetch-site, sec-gpc, sec-purpose, user-agent, x-forwarded-for, x-real-ip, x-requested-with
Header ที่เกี่ยวกับ security / PII
| Header | ใน log เป็นอย่างไร | Citation |
|---|---|---|
authorization | _REPLACED_ (redact สำเร็จ) | request_2023-04-20.log:1 |
apikey | ค่าจริงของ device key (redact พลาดเพราะ case apiKey vs apikey) | request_2023-04-20.log:1; logging.js:8 |
x-real-ip / x-forwarded-for | IP จริงของผู้ใช้ | request_2023-04-20.log:1 |
host | vtrcapi.redcross.or.th | request_2023-04-20.log:1 |
user-agent | ระบุ client (เช่น VTRC/1 CFNetwork/... สำหรับ mobile) | request_2023-04-20.log:1 |
5. variables — keys ที่พบใน sample
เมื่อ client ส่ง parameterized GraphQL จะมี object variables ตัวอย่าง keys ที่พบในชุด sample (ไม่ใช่ทุก key ทุกวัน):
address, adminCanPass, affiliation, age, apiKey, appVersion, approveStatus, approvers, attachFiles, birthDate, citizenId, clientType, confirmPassword, confirmNewPassword, department, description, docGroupId, email-related fields (sparse), empCode, empFirstName, empLastName, endDate, file, firstName, hospitalId, identityCard, lastName, leaveDay, leaveType, newPassword, oldPassword, organization, password, phoneNumber, postId, refreshToken, startDate, telNo, token, verificationCode, year, …
(รายการยาวเต็มจาก audit sample อยู่ใน research notes ของรอบนี้ — เอกสารเล่มนี้เน้นชนิดที่มีผลกระทบ PII)
Redaction ใน variables
เมื่อชื่อ key ตรงรายการใน replaceVariables ค่าจะเป็น _REPLACED_ — ตัวอย่าง:
"variables":{"oldPassword":"_REPLACED_","newPassword":"_REPLACED_","confirmNewPassword":"_REPLACED_"}(พบใน request_2023-04-19.log ตาม audit)
6. PII / secrets ที่ฝังใน query string (ไม่ถูก redact)
นี่คือช่องโหว่หลักของ request-log format — argument ถูก serialize เข้า query โดยตรง
| ชนิดข้อมูล | Pattern ใน query | ตัวอย่าง citation (ค่า redact ในเอกสาร) |
|---|---|---|
| เลขบัตรประชาชน 13 หลัก | sendVerifyCode(citizenId:"...") | request_2023-02-17.log (หลายบรรทัด; pattern ที่ app.js:10 ตั้งใจนับ) |
| วันเกิด | birthDate:"YYYY-MM-DD" ใน sendVerifyCode | บรรทัดเดียวกับ citizenId |
| รหัสพนักงาน | empCode:"..." | บรรทัดเดียวกับ citizenId |
| รหัสผ่าน login | login(... password:"..." ...) | request_2023-04-20.log (หลายบรรทัด) |
| รหัสผ่านเปลี่ยน | changePassword(oldPassword:... inline | ไฟล์ช่วงเมษายน 2023 |
| JWT / refresh | refreshToken(refreshToken:...,token:...) | request_2023-04-20.log |
| FCM device token | updateDeviceToken / updatePublicDeviceToken | request_2023-02-17.log |
| identityCard ใน slip | fetchSlip / fetchSlipPayDate / fetchSalaryCert | request_2023-04-20.log |
| captcha blob | checkRequestCaptcha(csId:...) | request_2023-02-17.log |
ตัวอย่างรูปแบบ (ค่าแทนด้วย placeholder):
sendVerifyCode(citizenId:"[REDACTED_13]",birthDate:"[REDACTED_DATE]",
organization:"3F3BF3AD-...",requestFor:CREATE_ACCOUNT,
empCode:"[REDACTED_EMP]",sendMethod:SMS)7. users.json fields
| Field | โครงสร้าง | Citation |
|---|---|---|
| (root) | string[] ของ UUID | users.json |
| count | 9,486 | parse JSON |
ไฟล์นี้เองคือรายชื่อผู้ใช้ (identifier) ที่ commit ใน git — จัดเป็น PII ระดับ identifier แม้ไม่มีชื่อ-นามสกุลในไฟล์
8. Output record ของ setData (เมื่อรัน script)
| Field | ความหมาย | Citation |
|---|---|---|
menu | string จาก menu[count] | app.js:132 |
user | UUID | app.js:132 |
type | JM / JW / OM / OW | app.js:132-141 |
date | dateStart ณ รอบนั้น | app.js:132 |
CSV ที่เคยออกแบบไว้ (comment): {date},{menu},{user},{type} (app.js:225)
9. สรุปความรุนแรงของ field inventory
| หมวด | อยู่ใน committed logs? | Redact โดย vtrc-api? |
|---|---|---|
| Bearer JWT ใน header | ไม่ (เป็น _REPLACED_) | ใช่ |
| Device apikey ใน header | ใช่ เต็ม | ไม่ (case mismatch) |
| Client IP | ใช่ | ไม่ |
| userId UUID | ใช่ | ไม่ |
| password ใน variables | เป็น _REPLACED_ | ใช่ |
| password ใน query text | ใช่ plaintext | ไม่ |
| citizenId ใน query text | ใช่ plaintext | ไม่ |
| Email ใน log body | ไม่พบ @... จากการ grep รอบ audit | — |
สำหรับ remediation ดู 04-scorecard — ลำดับแรกคือลบ/sanitize git history ของไฟล์ request_*.log และแก้ redaction ใน vtrc-api ให้ครอบคลุม inline query + header apikey