一、风险与目标风险:任意路径读取、MIME嗅探、内联脚本执行、文件名注入与目录遍历。目标:路径规范化与扩展名白名单、精确`Content-Type`与`nosniff`、安全`Content-Disposition`与UTF-8文件名。二、路径与类型校验import path from 'path' function normalizeSafe(root: string, rel: string): string | null { const p = path.normalize('/' + rel).replace(/^\/+/, '') const full = path.join(root, p) if (!full.startsWith(path.join(root, path.sep))) return null return full } const mimeMap: Record<string, string> = { '.pdf': 'application/pdf', '.txt': 'text/plain; charset=utf-8', '.csv': 'text/csv; charset=utf-8', '.zip': 'application/zip' } function contentTypeOf(ext: string): string | null { return mimeMap[ext.toLowerCase()] || null } 三、文件名规范化function safeFileName(name: string): string { const s = name.replace(/[\r\n\u0000]/g, '').replace(/[/\\]/g, '_') return s.slice(0, 200) } function disposition(name: string): string { const n = safeFileName(name) const encoded = encodeURIComponent(n) return `attachment; filename="${n}"; filename*=UTF-8''${encoded}` } 四、下载响应示例type Res = { setHeader: (k: string, v: string) => void; status: (n: number) => Res; end: (b?: string) => void } function sendDownload(res: Res, full: string, downloadName: string, fs: any) { const ext = path.extname(full) const ct = contentTypeOf(ext) if (!ct) return res.status(415).end('unsupported_media_type') res.setHeader('Content-Type', ct) res.setHeader('X-Content-Type-Options', 'nosniff') res.setHeader('Content-Disposition', disposition(downloadName)) res.setHeader('Cache-Control', 'private, max-age=0, no-store') const buf = fs.readFileSync(full) res.end(buf.toString('binary')) } 五、整合路由与验收type Req = { query: Record<string, string | undefined> } function handleDownload(req: Req, res: Res, fs: any) { const root = '/var/app/files' const rel = req.query['file'] || '' const name = req.query['name'] || 'download' const full = normalizeSafe(root, rel) if (!full) return res.status(400).end('invalid_path') sendDownload(res, full, name, fs) } 路径规范化通过且限制在根目录;扩展名白名单有效;`Content-Type`与`nosniff`设置正确。`Content-Disposition`为`attachment`且包含UTF-8文件名;缓存策略为私有且不存储。对不支持类型返回`415`;异常路径返回`400`;审计包含下载名与相对路径。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
1.905467s