From 48e3b58865aed535ae2054aeccb43ca4fcc9da13 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Wed, 1 Apr 2026 15:15:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(cors):=20=EC=9D=B8=EC=95=B1=20=EB=B8=8C?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=EC=A0=80=20CORS=20=EC=B0=A8=EB=8B=A8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20=E2=80=94=20=EC=B9=B4=ED=86=A1=20WebView?= =?UTF-8?q?=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - new Error() → cb(null, false): 500 에러 대신 CORS 헤더 미포함으로 거부 - *.technicalkorea.net 와일드카드 추가: 서브도메인 간 통신 보장 Co-Authored-By: Claude Opus 4.6 (1M context) --- sso-auth-service/index.js | 4 ++-- system1-factory/api/config/cors.js | 10 ++++++++-- system2-report/api/index.js | 4 ++-- tkpurchase/api/index.js | 4 ++-- tksafety/api/index.js | 4 ++-- tksupport/api/index.js | 4 ++-- user-management/api/index.js | 4 ++-- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/sso-auth-service/index.js b/sso-auth-service/index.js index bf0a200..d63c177 100644 --- a/sso-auth-service/index.js +++ b/sso-auth-service/index.js @@ -30,8 +30,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/(192\.168\.\d+\.\d+|localhost)(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/(192\.168\.\d+\.\d+|localhost)(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true })); diff --git a/system1-factory/api/config/cors.js b/system1-factory/api/config/cors.js index 8affcc1..93042fe 100644 --- a/system1-factory/api/config/cors.js +++ b/system1-factory/api/config/cors.js @@ -50,6 +50,12 @@ const corsOptions = { return callback(null, true); } + // *.technicalkorea.net 서브도메인 허용 (인앱 브라우저 대응) + if (/^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin)) { + logger.debug('CORS: technicalkorea.net 서브도메인 허용', { origin }); + return callback(null, true); + } + // 개발 환경에서는 모든 localhost 허용 if (process.env.NODE_ENV === 'development') { if (origin.includes('localhost') || origin.includes('127.0.0.1')) { @@ -64,9 +70,9 @@ const corsOptions = { return callback(null, true); } - // 차단 + // 차단 (500 에러 대신 CORS 헤더 미포함으로 거부) logger.warn('CORS: 차단된 Origin', { origin }); - callback(new Error(`CORS 정책에 의해 차단됨: ${origin}`)); + callback(null, false); }, /** diff --git a/system2-report/api/index.js b/system2-report/api/index.js index b404a71..e1196fd 100644 --- a/system2-report/api/index.js +++ b/system2-report/api/index.js @@ -29,8 +29,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true })); diff --git a/tkpurchase/api/index.js b/tkpurchase/api/index.js index 973036e..42514c3 100644 --- a/tkpurchase/api/index.js +++ b/tkpurchase/api/index.js @@ -25,8 +25,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true })); diff --git a/tksafety/api/index.js b/tksafety/api/index.js index f79c0e9..9fb4bf6 100644 --- a/tksafety/api/index.js +++ b/tksafety/api/index.js @@ -27,8 +27,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true })); diff --git a/tksupport/api/index.js b/tksupport/api/index.js index 44c20fb..7d78ddd 100644 --- a/tksupport/api/index.js +++ b/tksupport/api/index.js @@ -23,8 +23,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true })); diff --git a/user-management/api/index.js b/user-management/api/index.js index ede2766..f5d5974 100644 --- a/user-management/api/index.js +++ b/user-management/api/index.js @@ -42,8 +42,8 @@ if (process.env.NODE_ENV === 'development') { } app.use(cors({ origin: function(origin, cb) { - if (!origin || allowedOrigins.includes(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); - cb(new Error('CORS blocked: ' + origin)); + if (!origin || allowedOrigins.includes(origin) || /^https?:\/\/[a-z0-9-]+\.technicalkorea\.net$/.test(origin) || /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return cb(null, true); + cb(null, false); }, credentials: true }));