v0.3.3: 代码安全审查与Bug修复
CRITICAL 修复: - 路径遍历防护绕过:validatePath在normalize()之后检查..,可被绕过读取任意文件 - 编辑器异步创建竞态条件:editor.create()完成后组件已卸载导致内存泄漏 - editor.create() Promise缺少.catch() → 未捕获的Promise拒绝 - handleOpenRecent空文件被跳过:result.content truthy检查阻塞空文件打开 MAJOR 修复: - DIR_WATCH/TAB_SWITCHED IPC缺少路径校验,可被用于监视任意文件 - AboutDialog内联箭头函数使React.memo完全失效 - ConfirmDialog关闭时焦点恢复逻辑反转 - markdown.ts一刀切屏蔽..导致合法相对路径图片不显示 安全加固: - 移除未被使用的path.normalize导入 - 所有文件操作IPC使用validatePath统一校验 - 编辑器初始化添加cancelled标志防止卸载后设置实例 验证: TypeScript零错误, ESLint零错误零警告, 78/78测试通过
This commit is contained in:
@@ -3,18 +3,18 @@ import { readFileContent, saveFileContent, buildDirTree } from './file-system'
|
||||
import { FileWatcher, SidebarWatcher } from './file-watcher'
|
||||
import { IPC_CHANNELS } from '../shared/ipc-channels'
|
||||
import { stat } from 'fs/promises'
|
||||
import { basename, normalize, isAbsolute } from 'path'
|
||||
import { basename, isAbsolute } from 'path'
|
||||
|
||||
// 安全校验:拒绝路径遍历攻击
|
||||
function validatePath(filePath: string): boolean {
|
||||
if (!filePath || typeof filePath !== 'string') return false
|
||||
// 拒绝空字节
|
||||
if (filePath.includes('\0')) return false
|
||||
// 规范化路径后检查是否包含 ..
|
||||
const normalized = normalize(filePath)
|
||||
if (normalized.includes('..')) return false
|
||||
// 在 normalize 之前检查原始路径中的 .. 序列,防止 normalize 解析后绕过
|
||||
// 例如 '/valid/path/../../etc/shadow' normalize 后变为 '/etc/shadow',.. 已消失
|
||||
if (filePath.includes('..')) return false
|
||||
// 必须是绝对路径
|
||||
if (!isAbsolute(normalized)) return false
|
||||
if (!isAbsolute(filePath)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -185,6 +185,7 @@ export function registerIpcHandlers(
|
||||
|
||||
// 目录监听
|
||||
ipcMain.handle(IPC_CHANNELS.DIR_WATCH, (_event: IpcMainInvokeEvent, dirPath: string) => {
|
||||
if (!validatePath(dirPath)) return
|
||||
sidebarWatcher.start(dirPath)
|
||||
})
|
||||
|
||||
@@ -195,6 +196,10 @@ export function registerIpcHandlers(
|
||||
// 标签切换
|
||||
ipcMain.handle(IPC_CHANNELS.TAB_SWITCHED, (_event: IpcMainInvokeEvent, filePath: string | null) => {
|
||||
state.activeFilePath = filePath || null
|
||||
if (filePath && !validatePath(filePath)) {
|
||||
fileWatcher.stop()
|
||||
return
|
||||
}
|
||||
fileWatcher.start(filePath || '')
|
||||
const win = getMainWindow()
|
||||
if (win && !win.isDestroyed()) {
|
||||
|
||||
Reference in New Issue
Block a user