ui, 외부커넥션에서 쿼리 조회만 가능하도록
This commit is contained in:
@@ -91,7 +91,7 @@ async function executeMainDatabaseAction(
|
||||
}
|
||||
|
||||
/**
|
||||
* 외부 데이터베이스에서 데이터 액션 실행
|
||||
* 외부 데이터베이스에서 데이터 액션 실행 (보안상 비활성화)
|
||||
*/
|
||||
async function executeExternalDatabaseAction(
|
||||
tableName: string,
|
||||
@@ -99,29 +99,8 @@ async function executeExternalDatabaseAction(
|
||||
actionType: string,
|
||||
connection: any
|
||||
): Promise<any> {
|
||||
try {
|
||||
logger.info(`외부 DB 액션 실행: ${connection.name} (${connection.host}:${connection.port})`);
|
||||
logger.info(`테이블: ${tableName}, 액션: ${actionType}`, data);
|
||||
|
||||
// 🔥 실제 외부 DB 연결 및 실행 로직 구현
|
||||
const { MultiConnectionQueryService } = await import('../services/multiConnectionQueryService');
|
||||
const queryService = new MultiConnectionQueryService();
|
||||
|
||||
let result;
|
||||
switch (actionType.toLowerCase()) {
|
||||
case 'insert':
|
||||
result = await queryService.insertDataToConnection(connection.id, tableName, data);
|
||||
logger.info(`외부 DB INSERT 성공:`, result);
|
||||
break;
|
||||
case 'update':
|
||||
// TODO: UPDATE 로직 구현 (조건 필요)
|
||||
throw new Error('UPDATE 액션은 아직 지원되지 않습니다. 조건 설정이 필요합니다.');
|
||||
case 'delete':
|
||||
// TODO: DELETE 로직 구현 (조건 필요)
|
||||
throw new Error('DELETE 액션은 아직 지원되지 않습니다. 조건 설정이 필요합니다.');
|
||||
default:
|
||||
throw new Error(`지원하지 않는 액션 타입: ${actionType}`);
|
||||
}
|
||||
// 보안상 외부 DB에 대한 모든 데이터 변경 작업은 비활성화
|
||||
throw new Error(`보안상 외부 데이터베이스에 대한 ${actionType.toUpperCase()} 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -551,13 +551,18 @@ export class BatchExternalDbService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 외부 DB 테이블에 데이터 삽입
|
||||
* 외부 DB 테이블에 데이터 삽입 (보안상 비활성화)
|
||||
*/
|
||||
static async insertDataToTable(
|
||||
connectionId: number,
|
||||
tableName: string,
|
||||
data: any[]
|
||||
): Promise<ApiResponse<{ successCount: number; failedCount: number }>> {
|
||||
// 보안상 외부 DB에 대한 INSERT 작업은 비활성화
|
||||
return {
|
||||
success: false,
|
||||
message: "보안상 외부 데이터베이스에 대한 INSERT 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.",
|
||||
};
|
||||
try {
|
||||
console.log(`[BatchExternalDbService] 외부 DB 데이터 삽입: connectionId=${connectionId}, tableName=${tableName}, ${data.length}개 레코드`);
|
||||
|
||||
|
||||
@@ -937,23 +937,14 @@ export class DataflowControlService {
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE 액션 실행 - 조건 기반으로만 삭제
|
||||
* DELETE 액션 실행 - 보안상 외부 DB 비활성화
|
||||
*/
|
||||
private async executeDeleteAction(
|
||||
action: ControlAction,
|
||||
sourceData: Record<string, any>
|
||||
): Promise<any> {
|
||||
console.log(`🗑️ DELETE 액션 실행 시작:`, {
|
||||
actionName: action.name,
|
||||
conditions: action.conditions,
|
||||
});
|
||||
|
||||
// DELETE는 조건이 필수
|
||||
if (!action.conditions || action.conditions.length === 0) {
|
||||
throw new Error(
|
||||
"DELETE 액션에는 반드시 조건이 필요합니다. 전체 테이블 삭제는 위험합니다."
|
||||
);
|
||||
}
|
||||
// 보안상 외부 DB에 대한 DELETE 작업은 비활성화
|
||||
throw new Error("보안상 외부 데이터베이스에 대한 DELETE 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.");
|
||||
|
||||
const results = [];
|
||||
|
||||
|
||||
@@ -699,6 +699,30 @@ export class ExternalDbConnectionService {
|
||||
params: any[] = []
|
||||
): Promise<ApiResponse<any[]>> {
|
||||
try {
|
||||
// 보안 검증: SELECT 쿼리만 허용
|
||||
const trimmedQuery = query.trim().toUpperCase();
|
||||
if (!trimmedQuery.startsWith('SELECT')) {
|
||||
console.log("보안 오류: SELECT가 아닌 쿼리 시도:", { id, query: query.substring(0, 100) });
|
||||
return {
|
||||
success: false,
|
||||
message: "외부 데이터베이스에서는 SELECT 쿼리만 실행할 수 있습니다.",
|
||||
};
|
||||
}
|
||||
|
||||
// 위험한 키워드 검사
|
||||
const dangerousKeywords = ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER', 'TRUNCATE', 'EXEC', 'EXECUTE', 'CALL', 'MERGE'];
|
||||
const hasDangerousKeyword = dangerousKeywords.some(keyword =>
|
||||
trimmedQuery.includes(keyword)
|
||||
);
|
||||
|
||||
if (hasDangerousKeyword) {
|
||||
console.log("보안 오류: 위험한 키워드 포함 쿼리 시도:", { id, query: query.substring(0, 100) });
|
||||
return {
|
||||
success: false,
|
||||
message: "데이터를 변경하거나 삭제하는 쿼리는 허용되지 않습니다. SELECT 쿼리만 사용해주세요.",
|
||||
};
|
||||
}
|
||||
|
||||
// 연결 정보 조회
|
||||
console.log("연결 정보 조회 시작:", { id });
|
||||
const connection = await prisma.external_db_connections.findUnique({
|
||||
|
||||
@@ -119,22 +119,25 @@ export class MultiConnectionQueryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 대상 커넥션에 데이터 삽입
|
||||
* 대상 커넥션에 데이터 삽입 (보안상 외부 DB 비활성화)
|
||||
*/
|
||||
async insertDataToConnection(
|
||||
connectionId: number,
|
||||
tableName: string,
|
||||
data: Record<string, any>
|
||||
): Promise<any> {
|
||||
// 보안상 외부 DB에 대한 INSERT 작업은 비활성화
|
||||
if (connectionId !== 0) {
|
||||
throw new Error("보안상 외부 데이터베이스에 대한 INSERT 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.");
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info(
|
||||
`데이터 삽입 시작: connectionId=${connectionId}, table=${tableName}`
|
||||
);
|
||||
|
||||
// connectionId가 0이면 메인 DB 사용
|
||||
if (connectionId === 0) {
|
||||
return await this.executeOnMainDatabase("insert", tableName, data);
|
||||
}
|
||||
// connectionId가 0이면 메인 DB 사용 (내부 DB만 허용)
|
||||
return await this.executeOnMainDatabase("insert", tableName, data);
|
||||
|
||||
// 외부 DB 연결 정보 가져오기
|
||||
const connectionResult =
|
||||
@@ -288,7 +291,7 @@ export class MultiConnectionQueryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 대상 커넥션에 데이터 업데이트
|
||||
* 🆕 대상 커넥션에 데이터 업데이트 (보안상 외부 DB 비활성화)
|
||||
*/
|
||||
async updateDataToConnection(
|
||||
connectionId: number,
|
||||
@@ -296,6 +299,11 @@ export class MultiConnectionQueryService {
|
||||
data: Record<string, any>,
|
||||
conditions: Record<string, any>
|
||||
): Promise<any> {
|
||||
// 보안상 외부 DB에 대한 UPDATE 작업은 비활성화
|
||||
if (connectionId !== 0) {
|
||||
throw new Error("보안상 외부 데이터베이스에 대한 UPDATE 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.");
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info(
|
||||
`데이터 업데이트 시작: connectionId=${connectionId}, table=${tableName}`
|
||||
@@ -378,7 +386,7 @@ export class MultiConnectionQueryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 대상 커넥션에서 데이터 삭제
|
||||
* 🆕 대상 커넥션에서 데이터 삭제 (보안상 외부 DB 비활성화)
|
||||
*/
|
||||
async deleteDataFromConnection(
|
||||
connectionId: number,
|
||||
@@ -386,6 +394,11 @@ export class MultiConnectionQueryService {
|
||||
conditions: Record<string, any>,
|
||||
maxDeleteCount: number = 100
|
||||
): Promise<any> {
|
||||
// 보안상 외부 DB에 대한 DELETE 작업은 비활성화
|
||||
if (connectionId !== 0) {
|
||||
throw new Error("보안상 외부 데이터베이스에 대한 DELETE 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.");
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info(
|
||||
`데이터 삭제 시작: connectionId=${connectionId}, table=${tableName}`
|
||||
|
||||
Reference in New Issue
Block a user