NodeJS问题:用户可通过目录导航绕过路由处理器
问题根源
当你的Node应用放在cPanel的public_html/nrjs/目录下时,Apache服务器会优先处理静态文件请求。用户直接访问https://domain.tld/nrjs/protected/index.html时,Apache会直接从文件系统读取该文件并返回,完全不会将请求转发给你的Node.js应用,导致Express中的checkAuthenticated验证中间件根本无法生效。
解决办法
1. 用.htaccess强制所有请求经过Node.js应用
在public_html/nrjs/目录下创建/修改.htaccess文件,配置所有请求都转发给Node应用处理,让Express接管所有路由和静态文件验证:
RewriteEngine On # 替换为你的cPanel用户名 PassengerAppRoot "/home/yourusername/public_html/nrjs" # 替换为你的Node.js路径(可通过cPanel Node管理器查看) PassengerNodejs "/usr/local/bin/node" PassengerAppType node PassengerStartupFile app.js # 将所有请求重定向到Node应用入口 RewriteRule ^(.*)$ /nrjs/app.js/$1 [L]
配置完成后,所有HTTP请求都会先经过Express的中间件,你的checkAuthenticated就能正确拦截未认证用户访问protected内容的请求。
2. 调整目录结构,隔离protected目录
将protected目录移出public_html(比如放到/home/yourusername/nrjs-protected),然后通过Express路由来返回protected文件,而非直接使用express.static:
修改app.js中的静态文件配置:
// 移除原有的protected静态目录挂载 // app.use(basePath, checkAuthenticated, express.static(path.join(__dirname, 'protected'))); // 替换为路由级别的文件返回 app.get(basePath + '/index.html', checkAuthenticated, (req, res) => { res.sendFile(path.join(__dirname, '../nrjs-protected/index.html')); }); // 处理protected下的其他文件 app.get(basePath + '/protected/*', checkAuthenticated, (req, res) => { const filePath = req.params[0]; res.sendFile(path.join(__dirname, '../nrjs-protected', filePath)); });
这种方式下,protected目录完全不在Apache的web根目录范围内,用户无法直接通过URL访问,所有请求必须经过Express的认证验证。
3. 结合.htaccess和Express验证(不推荐,易出问题)
如果必须将protected放在public_html/nrjs/内,可通过.htaccess禁止Apache直接访问该目录,同时让Express负责验证后返回文件:
- 在
public_html/nrjs/protected/下创建.htaccess:
Order Deny,Allow Deny from all
- 修改
app.js的中间件顺序:
// 先挂载认证中间件到所有basePath路由 app.use(basePath, checkAuthenticated); // 再挂载静态目录,public无需额外验证,protected需先过认证 app.use(basePath, express.static(path.join(__dirname, 'public'))); app.use(basePath + '/protected', express.static(path.join(__dirname, 'protected')));
此方式中,用户直接访问protected文件会被Apache返回403,而经过Express认证后的请求,Node会直接读取文件返回(不受.htaccess限制)。但需注意cPanel的Passenger配置是否会影响文件读取权限。
内容的提问来源于stack exchange,提问作者Jacob

