使用 oAuth 的 GAE 端点上的 CSRF

CSRF on GAE Endpoints with oAuth

我希望在我的 API 中实施针对 CSRF 攻击的保护,这是我使用 GAE 端点开发的,所有方法都需要 oAuth2。

在实施任何特定保护之前,我试图真正破坏我的应用程序(CSRF 乍一看看起来很简单)。但是就是不能让它工作。

当我在另一个页面中引用我的端点时,浏览器会添加 cookie 信息,但不会添加带有不记名访问令牌的授权 header。这似乎还不够,因为我的端点自动 return 401 with a www-authenticate:Bearer realm="https://accounts.google.com/" header.

正如我所说,我没有针对 CSRF 的具体保护措施。但是,在 HTTPS 下使用 Google Cloud Endpoints 和 oAuth2 是否可以保护我免受此类攻击 "for free"?

--编辑 以解决评论

我尝试了一个简单的 CSRF 攻击。我得到一个 <img src="https://bla-bla-bla-appspot.com/_ah/api/myapi/v1/resource.getMethod"> 的页面。然后我在另一个选项卡中打开我的应用程序时访问了这个页面,所以我的浏览器会发送我的身份验证信息。它确实会发送 cookie,但不会发送我的 oAuth 令牌)。

我什至没有尝试过 POST,如果我 "hack" GET 就已经很棒了。

OAUth 2.0 explicitly protects against CSRF 通过使用由客户端生成并由服务器验证的 non-guessable 状态参数。即使攻击者能够诱使客户端访问 URL 以授权恶意令牌,状态参数也不会与客户端的参数匹配,请求将被拒绝。

Google Cloud Endpoints 库会为您处理 OAuth 规范的这一点,所以您没有问题。

Oauth2 要求所有请求都将承载访问令牌作为 HTTP header(使用来自 javascript 的 XMLhttpRequest 来设置 header 并发出请求)或作为 URL 查询参数 (access_token)。攻击者不会知道这个秘密值,因此无法创建可以通过验证的 URL。

这是(我希望)对我的 Kuoll remote debugger Web 应用有用的 java 片段。

package com.kuoll.server.filters;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CrossOriginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse resp = (HttpServletResponse) response;

        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
        resp.setHeader("Access-Control-Allow-Headers", "origin, content-type, accept");

        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

}

resp.addHeader("Access-Control-Allow-Origin", "*"); 中的 * 替换为您的来源(如果需要)。

web.xml

<filter-mapping>
    <filter-name>CrossOriginFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
</filter-mapping>