PHP中header跳转至Web根目录外页面及会员页防护问题
我有一个登录页面和会员页面,login.php位于网站根目录,代码如下:
include(ROOT_PATH.'server.php') ;//outside of web root ... login form: <form method="post" action="login.php"> <div class="input-group"> <label>username </label> <input type="text" name="username"> </div> <div class="input-group"> <label>Password</label> <input type="password" name="password" autocomplete="new-password"> </div> <div class="input-group"> <button type="submit" class="btn" name="login_user">Login</button> </div> </form>
server.php(位于Web根目录外)代码如下:
// LOGIN USER if (isset($_POST['login_user'])) { $username = $_POST['username']; $pass = $_POST['password']; //sanitize, check with database //if password valid, redirect to member page $_SESSION['username'] = $username; $_SESSION['user_id'] = $user_id; header('location:'.BASE_URL.'member.php'); exit; }
member.php代码如下:
session_start(); if (!isset($_SESSION['username']) && !isset($_SESSION['user_id'])) { header('location:login.php'); exit; } ... rest of the code
现咨询以下技术问题:
- 我计划将
member.php放置在Web根目录外,请问能否通过header('location')实现访问? - 若
member.php必须位于Web根目录,如何进一步增强该页面的访问防护措施?
1. 能否通过header('location')访问Web根目录外的member.php?
不行。header('location: ...')是向浏览器发送跳转指令,浏览器只能请求Web服务器对外暴露的资源(即Web根目录内的文件)。Web根目录外的文件不属于服务器的公开访问路径,浏览器无法直接请求到,因此直接用header跳转访问根目录外的member.php是无效的。
如果想让用户访问到根目录外的member.php内容,可以在Web根目录内创建一个代理脚本(比如member_entry.php),通过这个脚本包含根目录外的member.php,示例如下:
// member_entry.php(位于Web根目录) session_start(); // 先做登录校验 if (!isset($_SESSION['username']) || !isset($_SESSION['user_id'])) { header('location: login.php'); exit; } // 包含根目录外的member.php include(ROOT_PATH . 'member.php');
这样用户访问member_entry.php时,服务器会执行根目录外的member.php并返回内容,而浏览器始终只访问根目录内的脚本。
2. 增强Web根目录内member.php的访问防护措施
可以从以下几个方面强化防护:
完善会话校验逻辑
原代码的判断条件!isset($_SESSION['username']) && !isset($_SESSION['user_id'])存在逻辑问题,应该改为!isset($_SESSION['username']) || !isset($_SESSION['user_id'])(只要任意一个不存在就拦截)。此外,每次访问member.php时,建议从数据库验证$_SESSION['user_id']对应的用户是否真实存在,防止伪造的会话信息。配置安全的会话Cookie属性
在启动会话时设置Cookie的安全属性,防止会话劫持:session_start([ 'cookie_secure' => true, // 仅在HTTPS下传输Cookie 'cookie_httponly' => true, // 禁止JS读取Cookie,防范XSS窃取会话ID 'cookie_samesite' => 'Strict', // 限制Cookie跨站发送,防范CSRF 'cookie_lifetime' => 3600, // 设置会话有效期,比如1小时 ]);启用HTTPS协议
强制全站使用HTTPS,避免会话ID、用户名密码等敏感数据在传输过程中被明文窃取。会话ID定期刷新
用户登录成功或进行敏感操作时,生成新的会话ID并销毁旧会话,降低会话劫持风险:session_regenerate_id(true); // true表示销毁旧会话数据添加CSRF防护
如果member.php包含表单提交操作,需要生成CSRF令牌并验证:// 生成令牌并存入会话 if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // 在表单中添加隐藏字段 echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">'; // 处理请求时验证令牌 if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die('非法请求'); }限制登录失败次数
在server.php中记录用户的登录失败次数,达到阈值时锁定账号一段时间,防范暴力破解。防范XSS攻击
输出用户数据时使用htmlspecialchars()转义:echo htmlspecialchars($_SESSION['username'], ENT_QUOTES, 'UTF-8');使用数据库存储会话
替代默认的文件存储会话,便于管理会话生命周期,也能防止文件会话被非法读取。可以通过session_set_save_handler()自定义会话存储逻辑。
内容的提问来源于stack exchange,提问作者Toniq

