当前位置: 首页 > article >正文

Spring Security漏洞防护—HttpFirewall和 HTTPS

一、HttpFirewall

Spring Security有几个领域,你所定义的 pattern 会针对传入的请求进行测试,以决定应该如何处理请求。这发生在 FilterChainProxy 决定请求应该通过哪个过滤链时,以及 FilterSecurityInterceptor 决定哪些安全约束适用于请求时。在针对你定义的 pattern 进行测试时,了解该机制是什么以及使用什么URL值是很重要的。

servlet规范为 HttpServletRequest 定义了几个属性,这些属性可以通过 getter 方法访问,我们可能想与之匹配。这些属性是 contextPath、servletPath、pathInfo 和 queryString。Spring Security 只对应用程序中的路径安全感兴趣,所以 contextPath 被忽略了。不幸的是,servlet规范并没有准确地定义 servletPath 和 pathInfo` 的值对于一个特定的请求URI包含什么。例如,URL的每个路径段都可能包含参数,正如 RFC 2396 所定义的那样(你可能已经看到,当浏览器不支持cookies时,jsessionid 参数被附加到URL的分号之后。然而,RFC允许在URL的任何路径段中出现这些参数)。该规范没有明确说明这些参数是否应该包含在 servletPath 和 pathInfo 的值中,而且不同的servlet容器之间的行为也不同。存在这样一种危险:当应用程序部署在不从这些值中剥离路径参数的容器中时,攻击者可以将它们添加到请求的 URL 中,从而导致 pattern 匹配意外地成功或失败。一旦请求离开 FilterChainProxy,原始值将被返回,所以应用程序仍然可以使用)。传入的URL也有可能出现其他变化。例如,它可能包含路径遍历序列(如 /../)或多个正斜杠(//),也可能导致 pattern 匹配失败。一些容器在执行servlet映射之前会将这些内容规范化,但其他容器则不会。为了防止类似的问题,FilterChainProxy 使用 HttpFirewall 策略来检查和包装请求。默认情况下,未规范化的请求会被自动拒绝,路径参数和重复的斜线也会被删除,以便匹配。因此,例如,一个原始的请求路径为 /secure;hack=1/somefile.html;hack=2,被返回为 /secure/somefile.html)。因此,必须使用 FilterChainProxy 来管理安全过滤器链。请注意, servletPath 和 pathInfo 的值是由容器解码的,所以你的应用程序不应该有任何包含分号的有效路径,因为这些部分会被移除用于匹配目的。

如前所述,默认策略是使用 Ant 风格的路径进行匹配,这可能是大多数用户的最佳选择。该策略在 AntPathRequestMatcher 类中实现,该类使用Spring的 AntPathMatcher对servletPath 和 pathInfo 的连接模式进行不区分大小写的匹配,忽略 queryString。

如果你需要一个更强大的匹配策略,你可以使用正则表达式。那么这个策略的实现就是 RegexRequestMatcher。参见 该类的Javadoc以了解更多信息。

在实践中,我们建议你在服务层使用方法安全,以控制对你的应用程序的访问,而不是完全依赖使用在Web应用层定义的安全约束。URL会发生变化,而且很难考虑到一个应用程序可能支持的所有可能的URL,以及请求可能被操纵的方式。你应该限制自己使用一些简单的Ant路径,这些路径很容易理解。始终尝试使用 “deny-by-default” 的方法,在这里你有一个万能的通配符(/** 或 **)最后定义来拒绝访问。

在服务层定义的安全更强大,更难绕过,所以你应该始终利用Spring Security的方法安全选项。

HttpFirewall 还通过拒绝HTTP响应头中的换行字符来防止 HTTP响应分裂。

默认情况下,使用 StrictHttpFirewall 实现。这个实现会拒绝那些看起来是恶意的请求。如果它对你的需求来说过于严格,你可以自定义拒绝哪些类型的请求。然而,重要的是,你要知道这样做会使你的应用程序受到攻击。例如,如果你希望使用Spring MVC的 matrix 变量,你可以使用以下配置。

Allow Matrix Variables

  • Java
@Bean
public StrictHttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowSemicolon(true);
    return firewall;
}

为了防止 跨站追踪(XST) 和 HTTP Verb Tampering,StrictHttpFirewall 提供了一个允许的有效 HTTP 方法列表。默认的有效方法是 DELETE、GET、HEAD、OPTIONS、PATCH、POST 和 `PUT。如果你的应用程序需要修改有效方法,你可以配置一个自定义的 StrictHttpFirewall Bean。下面的例子只允许HTTP GET 和 POST 方法。

Allow Only GET & POST

  • Java
@Bean
public StrictHttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST"));
    return firewall;
}

如果你使用 new MockHttpServletRequest(),它目前创建的HTTP方法是一个空字符串("")。这是一个无效的HTTP方法,会被Spring Security拒绝。你可以用 new MockHttpServletRequest("GET", "") 代替它来解决这个问题。请参阅 SPR_16851,该问题要求改进这一点。

如果你必须允许任何 HTTP 方法(不推荐),你可以使用 StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)。这样做可以完全禁止对HTTP方法的验证。

StrictHttpFirewall 还检查头名称和值以及参数名称。它要求每个字符都有一个定义好的码位(code point),并且不是一个控制字符。

这一要求可以通过以下方法在必要时放宽或调整。

  • StrictHttpFirewall#setAllowedHeaderNames(Predicate)
  • StrictHttpFirewall#setAllowedHeaderValues(Predicate)
  • StrictHttpFirewall#setAllowedParameterNames(Predicate)

参数值也可以用 setAllowedParameterValues(Predicate) 来控制。

例如,为了关闭这个检查,你可以在你的 StrictHttpFirewall 中加入总是返回 true 的 Predicate 实例。

Allow Any Header Name, Header Value, and Parameter Name

  • Java
@Bean
public StrictHttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowedHeaderNames((header) -> true);
    firewall.setAllowedHeaderValues((header) -> true);
    firewall.setAllowedParameterNames((parameter) -> true);
    return firewall;
}

另外,可能有一个特定的值,你需要允许。

例如,iPhone Xʀ 使用的 User-Agent 包括一个不属于 ISO-8859-1 字符集的字符。由于这一事实,一些应用服务器将这个值解析为两个独立的字符,后者是一个未定义的字符。

你可以用 setAllowedHeaderValues 方法解决这个问题。

Allow Certain User Agents

  • Java
@Bean
public StrictHttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    Pattern allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*");
    Pattern userAgent = ...;
    firewall.setAllowedHeaderValues((header) -> allowed.matcher(header).matches() || userAgent.matcher(header).matches());
    return firewall;
}

如果是 header 值,你可以考虑在验证时将其解析为UTF-8。

Parse Headers As UTF-8

  • Java
firewall.setAllowedHeaderValues((header) -> {
    String parsed = new String(header.getBytes(ISO_8859_1), UTF_8);
    return allowed.matcher(parsed).matches();
});

二、重定向到 HTTPS

如果客户端使用HTTP而不是HTTPS发出请求,你可以配置Spring Security重定向到HTTPS。

例如,下面的Java或Kotlin配置将任何HTTP请求重定向到HTTPS。

Redirect to HTTPS

  • Java

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.requiresChannel(channel -> channel
				.anyRequest().requiresSecure()
			);
		return http.build();
	}
}

下面的XML配置将所有HTTP请求重定向到HTTPS

Redirect to HTTPS with XML Configuration

<http>
	<intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
...
</http>

http://www.kler.cn/a/107827.html

相关文章:

  • 数字后端教程之Innovus report_property和get_property使用方法及应用案例
  • Window下PHP安装最新sg11(php5.3-php8.3)
  • 什么岗位需要学习 OpenGL ES ?说说 3.X 的新特性
  • 蔚来Java面试题及参考答案
  • influxDB 时序数据库安装 flux语法 restful接口 nodjsAPI
  • 微服务day07
  • StripedFly恶意软件框架感染了100万台Windows和Linux主机
  • 0基础学习PyFlink——用户自定义函数之UDTAF
  • Git 拉取远程更新报错
  • Linux音频-基本概念
  • 记录--vue3实现excel文件预览和打印
  • NewStarCTF2023week4-Nmap
  • 【华为OD:C++机试】Day-1
  • 已解决:conda找不到对应版本的cudnn如何解决?
  • K8s 部署 CNI 网络组件+k8s 多master集群部署+负载均衡
  • 猴子吃桃问题--C语言
  • 计算机操作系统重点概念整理-第五章 文件管理【期末复习|考研复习】
  • 不再受害:如何预防和应对.mallab勒索病毒攻击
  • Mac运行Docker报错
  • shell实现部署ftp提供共享yum仓库
  • QT中获取当前项目路径的写法
  • 已有wchar_t *类型的filepath,使用Qt打开该文件
  • CLIP文章精读
  • 【计算机毕设经典案例】基于微信小程序的图书管理系统
  • 水性杨花:揭秘CSS响应式界面设计,让内容灵活自如,犹如水之变幻
  • synchronized 的锁类型