Skip to content

4.8 · Security + debt

บทนี้ catalog ความเสี่ยงด้านความปลอดภัยและ technical debt ของ cu-central-api โดยเน้นสิ่งที่ต่างจาก vtrc-api (ส่วนที่เหมือนกัน cover ใน Volume 9 แล้ว)


Severity summary

SeverityCount
🔴 Critical4
🟡 High6
🟢 Medium4

🔴 Critical

C1 · JWT_SECRET default empty string

16:17:main-api/src/config.js
  JWT_ISSUER = '',
  JWT_SECRET = '',
9:11:main-api/src/lib/jwtToken.js
const getPrivayeKey = () => {
  return JWT_SECRET
}

🔴 default เป็น empty string — และ jsonwebtoken@8.5.1 ยอม sign ด้วย empty string (ไม่ throw)

ถ้า env unset ใน deployment ใด — service จะ boot และ sign token จริงด้วย secret "" ทำให้ทุกคนสามารถ forge JWT ได้

ไม่มี guard แบบ if (IS_PRODUCTION && !JWT_SECRET) throw ที่จะ hard-fail ที่ boot

typo getPrivayeKey (ควรเป็น getPrivateKey) — ไม่มี impact แต่บ่งบอกว่าไม่มี code review ที่จริงจัง

C2 · apiKeys hardcoded ใน code

253:274:main-api/src/lib/auth/auth.controller.js
const allowedApiKeys = [
  {
    apiKey: 'OGJlYTEzOTBjMzk3NjlmYWQ1ZTcxZDZhN2NhZWMyYTk3YTQ2NGIzMDhiMGM4NmRjM2NlNjZkM2I2ZDIyOGQyMQ',
    ...
  },
  {
    apiKey: '562B132B1E87695A052717C20336CDA57FBC4C5B19EF31356CC07C5A43656DE47DEFE452D241C3F443DE54',
    ...
  }
]

(apiKeys ที่ commit — detail ในบท 4.4)

C3 · .env.develop-test committed

ไฟล์ .env.develop-test ที่มี UAT secrets ทั้งหมด commit อยู่ใน repo — cover ใน Volume 9.5 (cu-central-api inventory)

C4 · axois typosquat

main-api/package.json:20
"axois": "0.0.1-security",

🔴 typosquat ของ axios — npm reserve 0.0.1-security สำหรับ typosquatted packages

  • codebase ไม่ได้ import axois จริง (grep confirms 0 imports)
  • แต่ npm install ยัง pull package เข้า node_modules
  • ถ้า typosquat มี postinstall script → execute ตอน install

C5 · httpRequest.js ใช้ axios ที่ไม่ได้ declare

1:1:main-api/src/lib/httpRequest.js
import axios from 'axios'
19:19:main-api/src/lib/httpRequest.js
const result = await axios(options)
  • import axios แต่ dependencies มีแค่ axois (typo)
  • ถ้ามี code path ใดถึง httpRequest.js — crash ทันที

🟡 High

H1 · error-ex git URL dependency

main-api/package.json:25
"error-ex": "git+https://github.com/Qix-/node-error-ex.git",

🟡 pin ไปที่ git URL แทน npm version — mutable ref ไม่มี hash protection ถ้า upstream repo compromised

H2 · ldapjs unmaintained

main-api/package.json:30
"ldapjs": "^2.2.0",

🟡 project archived ตั้งแต่ 2023 — fork ldapts เป็น successor ที่ active

H3 · jsonwebtoken@8 CVE

main-api/package.json:34
"jsonwebtoken": "^8.5.1",

🟡 8.x EOL — CVE-2022-23529 family มี patch ใน v9+

H4 · rejectUnauthorized: false ใน LDAP

20:21:main-api/src/lib/auth/activeDirectory.connector.js
const tlsOptions = {
  rejectUnauthorized: false,
}

🟡 ปิด TLS cert verification บน LDAP connection — MITM สามารถ intercept password ของ user

H5 · Node 12 + esm shim

main-api/Dockerfile:1
FROM node:12.18.3
main-api/package.json:27
"esm": "^3.2.25",

🟡 Node 12 EOL April 2022 — 4+ ปีไม่มี security patch

esm shim (last release 2019) เป็น root cause ที่ lock codebase ไว้ที่ Node 12

H6 · xlsx CVE history

main-api/package.json:45
"xlsx": "^0.16.9",

🟡 SheetJS community มี prototype pollution CVE history — เวอร์ชันปัจจุบันอยู่บน SheetJS CDN (ไม่ใช่ npm)


🟢 Medium

M1 · clockTolerance ใน JWT payload (misuse)

33:34:main-api/src/lib/jwtToken.js
return { ...payload, clockTolerance: 5 }

clockTolerance เป็น jwt.verify option — ใส่เป็น payload claim ไม่มีผล เป็น misuse ของ jsonwebtoken API

M2 · signinDomains hardcoded

resolvers/authentication.js:35-72 — 26 rows ของ org list hardcoded ใน code

การเพิ่ม/แก้ org ต้อง deploy code ใหม่ — ควรย้ายไป masterData table

M3 · dbHRMI_test dead connection

117:142:main-api/src/connector.js
const dbHRMI_test = new Sequelize("dbHRMI_test", ...)

connection pool ที่เปิดขึ้นทุก boot แต่ไม่มี model ผูก — เปลือง MSSQL resource

M4 · OTP inconsistency

hr/hrAddress.js ปิด OTP ตั้งแต่ 8 Jul 2021 แต่ hr/hrPhoneNumber.js ยังทำงาน — sibling resolvers ใช้ pattern ต่างกัน


Audit cross-reference

mapping กับ audit/05-tech-debt-register.md

Debt IDChapterTopic
SEC-7C4, C5axois typosquat + httpRequest.js broken
SEC-8C3.env.develop-test committed
SEC-9H1error-ex git URL
LEG-1H5Node 12 EOL
LEG-2H5esm shim lock-in
LEG-3(Volume 3)apollo-server v2 EOL
LEG-8H2ldapjs unmaintained
LEG-9H3jsonwebtoken v8 CVE
LEG-27H6xlsx prototype pollution
LEG-28sha512crypt-node (ใช้ใน activeDirectory.js:5)
CORR-9C5httpRequest.js broken

Comparison กับ vtrc-api security

Aspectvtrc-apicu-central-api
JWT secret default'secret''' (empty)
apiKeysใน config.js (7 prod)hardcoded 2 keys
Password handlingforward plaintext ไป centralizeverify ผ่าน LDAP โดยตรง
execSync injection🔴 5 endpoints🟢 ไม่มี
SQL injection🔴 statLog.js🟢 ไม่พบ
CORS bug🔴 corss typo🟢 ไม่มี (ไม่ได้ set CORS)
introspection prod🔴 true เสมอ🟢 gate ด้วย IS_PRODUCTION
File upload🔴 multer no filter🟢 ไม่มี file upload endpoint
Rate limit🔴 ไม่มี🔴 ไม่มี

cu-central-api มี security posture ที่ดีกว่า vtrc-api ในหลายด้าน (ไม่มี execSync, ไม่มี SQLi, gate introspection ถูก) แต่แย่กว่าในเรื่อง LDAP TLS และ ignoreAuth bypass


Modernization path

ตาม audit/05-tech-debt-register.md §5.3 cu-central-api ทั้งหมดควร decompose เป็น 2 Go services

cu-central-api (Node 12)


┌──────────────────┐    ┌──────────────────┐
│  identity-service │    │  hr-data-service  │
│  (Go + Hex/DDD)  │    │  (Go + Hex/DDD)   │
└──────────────────┘    └──────────────────┘
        │                        │
        │                        ├──▶ MSSQL (per-shard connection)
        │                        ├──▶ HRMI HTTP API
        │                        └──▶ HIS API

        ├──▶ LDAP/AD (go-ldap)
        ├──▶ Redis (go-redis)
        ├──▶ JWT (golang-jwt/jwt/v5)
        └──▶ Casbin (RBAC policy)
Contextเหตุผลที่แยก
identity-serviceauth + RBAC + session เป็นส่วนงานที่ใช้ร่วมกันทุก service — ควรแยกเป็น service เดียวที่ทุกคนเรียก
hr-data-serviceการอ่าน/เขียน HR data เป็นงานเฉพาะตัว — มี SourceDB sharding เป็นรายละเอียดภายใน

รายละเอียดเพิ่มเติมใน Volume 15


Wave 0 stop-the-bleed checklist

#ActionSeverityEffort
1Rotate JWT_SECRET + hard-fail at boot ถ้า empty🔴 C10.5d
2Rotate hardcoded apiKeys + ย้ายไป env🔴 C21d
3Purge .env.develop-test + rotate secrets🔴 C31-2d
4ลบ axois typosquat + add axios@^1.x🔴 C4, C50.5d
5Fix rejectUnauthorized: false ใน LDAP🟡 H41d

รวม Wave 0 ≈ 4-5 วัน — ลด Critical ทั้งหมด


อ่านต่อ → 4.9 Scorecard + comparison