request.getHeader("Origin") 如何防止跨站请求伪造攻击?

Posted

技术标签:

【中文标题】request.getHeader("Origin") 如何防止跨站请求伪造攻击?【英文标题】:How request.getHeader("Origin") prevents from Cross Site Request Forgery attacks? 【发布时间】:2017-01-10 17:20:16 【问题描述】:

我正在开发 Web 应用程序,并要求在发布前针对它运行 VAPT

然后我下载了Vega并快速扫描了我的webapp,发现了一个VAPT问题,如下:

Vega 检测到资源设置了不安全的跨域 资源共享 (CORS) 访问控制。 CORS 提供的机制 允许服务器限制跨站点请求的资源访问 某些受信任的域。有问题的服务器已允许资源 通过设置的值从任何来源 通配符值的“Access-Control-Allow-Origin”响应标头。 这会带来安全风险,因为任何站点都可以向 访问资源,无论来源。

然后我开始寻找解决方案并遇到this 帖子并按照答案中的建议实施了filter,如下所示:

@Component
public class CORSFilter implements Filter 

    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
    

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException 
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods",
                "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(request, response);
    

    public void destroy() 
    

现在,当我再次针对 webapp 扫描 Vega 时,它没有再次列出相同的问题,我相信这使我的 webapp 免受CSRF 攻击。

现在,在阅读了this 的帖子后,我正在思考request.getHeader("Origin") 如何防止Cross Site Request Forgery attacks,因为无论来源是https://webapp.com 还是https://evil.com,请求始终对我的应用程序有效从请求标头本身中选择"Access-Control-Allow-Origin"

谁能帮我理解这个概念,设置request.getHeader("Origin")如何从CSRF attacks保存?

谢谢。

阅读@rism 答案和 Patrick Grimard post 后了解:

当客户端应用程序发出 AJAX 请求时,浏览器最初会向服务器发送预检 OPTIONS 请求以确定允许客户端执行的操作,而不是 GET,这就是我们应该设置 @987654340 的原因@ 作为响应标头的一部分的源或特定域。

POST为例,当客户端发送请求时,浏览器首先向服务器发出预检OPTIONS请求,服务器对OPTIONS请求的响应包含指示浏览器的所有origin请求的标头是允许的。除了添加response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); 站点仍然容易受到攻击,因此我们需要在 Apache(对于部署在集群中的应用程序)中明确地whitelist IP 的完成,如 here 或在 Tomcat 中描述的 here。

我还有一个疑问,如果我们在服务器级别限制 IP 地址,是否真的需要将 "Access-Control-Allow-Origin" 设置为响应标头的一部分?

【问题讨论】:

如果您使用的是最新版本的 spring security 内置的 cors 支持,您不必编写过滤器 是的,您仍然需要发送 ACAO 标头,因为尽管 IP 限制可能会限制可接受的绑定 IP 范围,但请求仍可能是跨源的。因此,尽管 IP 限制可能充当白名单,但如果没有 ACAO 标头,您仍然无法执行 CORS。即使是从 a.example.com 到 b.example.com 的请求也是跨域的,如果使用 AJAX,则需要 CORS 标头。 明确地说,CORS 实际上是 html5 规范的客户端技术部分。所以我假设你在谈论来自客户端浏览器的 AJAX 请求?否则,如果您实际上是在谈论服务器到服务器的调用,那么 CORS 根本不相关,因为它是执行同源策略的浏览器,而不是服务器。 @rism:我只关心来自客户端浏览器的 AJAX 请求,也感谢您消除疑问! 【参考方案1】:

它有助于理解 CSRF 攻击的目的。它们不是关于“窃取”您的数据。顾名思义,它们是关于“跨站点发出伪造请求”,即跨站点请求伪造,即 CSRF。

目的是通过涉及银行帐户的规范示例更改服务器上的状态。通过 CSRF 攻击,我们试图以您的名义伪造一个请求(转账 100 美元)。

所以简单的例子是攻击者将脚本或隐藏表单等注入any site 上的页面,例如www.cutekittens.com 并让该脚本以specific site 为目标,例如www.mybank.com 因此称为Cross Site

这个想法是,您作为受害者将同时登录到两个站点,而银行站点的安全性松懈。当您在 www.cutekittens.com 查看可爱的小猫时,攻击者已将跨站点攻击脚本注入其中一个或多个页面。该脚本的目的是代表您向您的银行 www.mybank.com 提出转账 100 美元的请求。

在这里再次注意,攻击者并没有窃取您的数据,而是试图以您的名义提出伪造请求来窃取您的钱/其他任何东西。这不是man in the middle 攻击(MITM),而是请求伪造攻击。在 CSRF 中,攻击者不会看到或不需要看到您的数据,他们只是想办法让自己像您一样行事。这样做的后续目的可能是获取您的数据,例如更改您的密码等,但攻击本身是关于发出伪造请求,而不是关于拦截。

因此,银行可以保护自己及其客户的一种方法是明确说明哪些网站可以通过CORS 标头向其提出请求。

如果他们没有特别包含 www.cutekittens.com,那么即使攻击者设法将他们的恶意脚本注入到 www.cutekittens.com 网站上的页面中,即使您碰巧同时浏览了两个可爱小猫和你的银行网站,即使执行了攻击脚本,对 www.yourbank.com 的请求也会被丢弃(在预检 POST 之后),因为银行没有向浏览器发送标头ACCESS-CONTROL-ALLOW-ORIGIN : www.cutekittens.com专门授权该请求。

所以你是对的。通过用动态request.getHeader("Origin") 替换此标头的静态* 值,您所做的一切就是让Vega 摆脱困境。如果你的网站写得不好,它仍然可能容易受到这种攻击,因为它会反射回 www.cutekittens.com,这可能不是你想要的。

您使用request.getHeader("Origin") 而不是* 的一个原因是您想向服务器发送凭据。您不能发送凭据,例如将 CORS AJAX 请求上的 cookie 等发送到仅使用 * 的服务器,因此在这种情况下,您将动态地将源反射回客户端。

但是通过这样做,您确实需要确保以其他方式降低风险。在这种情况下,您通常还会将您将反映和不会反映的内容列入白名单。例如portal.mybank.com 可能在列表中,但 www.cutekittens.com 不会。如果您要使用动态原点反射,那么这将是您可以实施的下一步。

【讨论】:

感谢您提供详细而精彩的解释,根据您的回答我更新了我的问题,请看看并分享您的想法。

以上是关于request.getHeader("Origin") 如何防止跨站请求伪造攻击?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中request.getHeader(String param)获取的啥值

request.getHeader("Origin") 如何防止跨站请求伪造攻击?

web页面防盗链功能使用--request.getHeader("Referer")

java中String browser = request.getHeader("user-agent")报空指针异怎么解决

Spring mvc 如何启动 socket

request.getheader怎么用