登录框之另类思考:来自客户端的欺骗
字数 1109 2025-08-18 11:37:23
客户端欺骗登录框漏洞分析与防御指南
0x01 漏洞背景
在Web应用安全测试中,登录框是常见但容易被忽视的攻击面。传统防护措施如风控系统、验证码、SSO登录和OAuth授权已经相对成熟,攻击者需要寻找新的突破点。
0x02 漏洞特征发现
通过Fuzz后台目录发现异常现象:
- 所有请求返回状态码均为200
- 不同页面的响应Size不同
- 访问受限页面(如
/system/user/index/)时被重定向到首页,但仍返回200状态码
0x03 正常鉴权流程
- 客户端向服务端发起请求
- 服务端全局过滤器判断访问权限
- 权限不足时可能返回:
- 200状态码+错误页面
- 302跳转登录页
- 403无权限
- 500越权异常
- 权限不足时可能返回:
- 权限足够则继续执行业务逻辑
0x04 异常流程分析
- 客户端发起请求
- 服务端接口直接响应(未做权限检查)
- 浏览器解析响应内容
- 前端JS检查Cookie中的权限标志,决定是否跳转
关键矛盾点:
- 返回200状态码但跳转登录页
- 不同URL返回不同Size的响应内容
0x05 漏洞利用方法
脆弱点分析
- 缺乏服务端权限校验:依赖前端JS做权限判断
- 前端可篡改:Cookie标志、JS逻辑都可被修改
实际案例
案例一:前端鉴权绕过
- 通过F12查看源码,发现使用Ajax异步登录
- 分析发现登录成功跳转逻辑在前端JS中实现
- 直接访问后台接口返回200但被前端JS重定向
- 可篡改前端获取的RoleID等权限标识
案例二:拦截式攻击
- 直接访问受限接口返回HTML+JS跳转代码
- 拦截响应,删除
location.href跳转逻辑 - 获取原始接口响应,可能包含敏感数据
- 构造请求直接调用业务接口
0x06 安全防护方案
基于角色的权限控制实现(Java示例)
项目结构
src/
main/
java/
com/screw/
controller/TestHello.java
util/PrivilegeFilter.java
resources/
webapp/
WEB-INF/
privilege.properties
web.xml
权限配置文件(privilege.properties)
admin=admin
user=admin,user
login=guest,user,admin
过滤器实现(PrivilegeFilter.java)
public class PrivilegeFilter implements Filter {
private Properties properties = new Properties();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String fileName = filterConfig.getInitParameter("privilegeFile");
String realPath = filterConfig.getServletContext().getRealPath(fileName);
try {
properties.load(new FileInputStream(realPath));
} catch(Exception e) {
filterConfig.getServletContext().log("读取权限控制文件失败",e);
}
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String requestUri = request.getRequestURI().replace(request.getContextPath(), "");
String role = (String)request.getSession().getAttribute("role");
role = role == null ? "guest" : role;
boolean authen = false;
for(Object obj : properties.keySet()) {
String key = (String)obj;
if(requestUri.indexOf(key) != -1) {
if(((String) properties.get(key)).indexOf(role) != -1) {
authen = true;
break;
}
}
}
if(!authen) {
throw new RuntimeException("您无权访问该页面。");
}
chain.doFilter(request, response);
}
}
web.xml配置
<filter>
<filter-name>PrivilegeFilter</filter-name>
<filter-class>com.screw.util.PrivilegeFilter</filter-class>
<init-param>
<param-name>privilegeFile</param-name>
<param-value>/WEB-INF/privilege.properties</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrivilegeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
测试Controller
@Controller
public class TestHello {
@RequestMapping(value = "/login", method=RequestMethod.GET)
public String login() { return "login"; }
@RequestMapping(value = "/login", method=RequestMethod.POST)
public String login(String username, String passwd, HttpSession session) {
if(username.equals("admin") && passwd.equals("123456")) {
session.setAttribute("role", "admin");
} else if (username.equals("user") && passwd.equals("123456")) {
session.setAttribute("role", "user");
} else {
return "login";
}
return "index";
}
@RequestMapping("/admin/index")
public String admin() { return "admin"; }
@RequestMapping("/user/add")
public String add() { return "add"; }
}
0x07 关键防护要点
- 服务端全局拦截:在请求到达业务逻辑前进行权限校验
- 基于角色的访问控制(RBAC):
- 定义清晰的权限层级(admin/user/guest)
- 配置文件管理URL-角色映射关系
- 统一错误处理:
- 权限不足时返回明确的错误(403)
- 避免返回200状态码+前端跳转
- 会话管理:
- 权限标识存储在服务端Session中
- 避免依赖前端可修改的标识(Cookie/JS变量)
0x08 总结
客户端欺骗漏洞的核心问题是权限校验的"前端化"。有效的防护必须:
- 在服务端实现全局权限拦截
- 建立完善的基于角色的访问控制机制
- 避免信任任何来自客户端的安全判断
- 采用统一、明确的无权限响应方式