【问题标题】:Gorilla CSRF with AngularJS带有 AngularJS 的 Gorilla CSRF
【发布时间】:2016-02-14 04:23:14
【问题描述】:

我正在尝试让 AngularJS 与 Gorilla CSRF 一起用于我的 Web 应用程序,但是我找不到很多文档,所以我不确定从哪里开始。我应该为每个GET 请求设置X-CSRF-Token,还是应该像现在这样在用户访问主页时这样做?另外,如何使 AngularJS CSRF 保护与 Gorilla CSRF 一起工作?我需要做一些比较吗?任何示例代码将不胜感激。

这是我的代码:

package main

import (
    "github.com/gorilla/csrf"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()


    r.HandleFunc("/", Home).Methods("GET")
    // Other routes handling goes here

    http.ListenAndServe(":8000",
        csrf.Protect([]byte("32-byte-long-auth-key"))(r))
}

func Home(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("X-CSRF-Token", csrf.Token(r))
}
// More routes

【问题讨论】:

    标签: angularjs go gorilla


    【解决方案1】:

    您的问题可能有点宽泛,但总体而言您滥用了这些工具,因此我将尝试解释基本思想。您正在使用的应用程序使用“双重提交”模式进行 CSRF 保护。这需要更改客户端和服务器代码库。服务器不应该设置X-CSRF-Token 标头,这是客户端的角色。实际上,我最近从头开始实施了几个反 CSRF 解决方案,它们非常简单(都是双重提交模式)。我还使用了一些来自 MSTF 和 Apache 等供应商的软件包(必须在各种堆栈上的 20 年应用程序中实现 CSRF)。

    在双重提交模式中,服务器应该设置一个具有随机值的 cookie(如 guid),该 cookie 必须被标记为安全的。您也可以将其设为 httponly,但是这需要您在前端资源上做更多的工作。在客户端,处理这个问题的最简单方法是实现一些 JavaScript,它读取 cookie 值并将其作为标头添加到任何 POST 请求之前。您通常不需要保护 GET。你可以,但如果你的 GET 在服务器端做建设性/破坏性的事情,那么你就在滥用 HTTP 动词,我会通过将这些请求发布为 POSTS 而不是试图保护每一个请求来纠正这一点。

    在服务器端,最好在所有请求都进来的公共地方预先进行 CSRF 检查。当 POST 进来时,服务器应该读取 cookie 值,检查标头值并比较它们.如果它们相等,则应允许请求通过,如果不相等,则应使用 403 或其他方式将它们启动。这样做之后,服务器应该重写 cookie 值(最好只使用一次)。

    您的客户端脚本可以有类似下面的代码,只要确保资源在每个页面加载并且您不使用表单提交,这将涵盖所有内容。如果您提交表单,您将需要一些其他类似的代码来处理它。有些方法更喜欢将值写入 DOM 服务器端。例如,在 .NET 中,CSRF 库将值设置为 HTTPOnly 和 Secure,并希望开发人员在项目中的每个 cshtml 文件中的每个表单中都放置一个占位符令牌......我个人认为这是非常愚蠢和低效的。不管你怎么做,你可能不得不做一些定制工作。 Angular 不会为 gorillas CSRF 库实现前端。 gorilla 可能不会为您的客户端附带 JavaScript,因为它是一个 API 库。无论如何,基本的 JavaScript 示例;

    // three functions to enable CSRF protection in the client. Sets the nonce header with value from cookie
    // prior to firing any HTTP POST.
    function addXMLRequestCallback(callback) {
        var oldSend;
        if (!XMLHttpRequest.sendcallback) {
            XMLHttpRequest.sendcallback = callback;
            oldSend = XMLHttpRequest.prototype.send;
    
            // override the native send()
            XMLHttpRequest.prototype.send = function () {
                XMLHttpRequest.sendcallback(this);
    
                if (!Function.prototype.apply) {
                    Function.prototype.apply = function (self, oArguments) {
                        if (!oArguments) {
                            oArguments = [];
                        }
                        self.__func = this;
                        self.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
                        delete self.__func;
                    };
                }
    
                // call the native send()
                oldSend.apply(this, arguments);
            }
        }
    }
    
    addXMLRequestCallback(function (xhr) {
        xhr.setRequestHeader('X-CSRF-Token', getCookie('X-CSRF-Cookie'));
    });
    
    function getCookie(cname) {
        var name = cname + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1);
            if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
        }
        return "";
    }
    

    现在,如果您可以稍微缩小您的问题范围,我可以提供一些更具体的指导,但这只是一个猜测(也许我会在有时间的时候阅读他们的文档)。如果您使用csrf.Protect,Gorilla 会自动设置您的 cookie 并为您进行服务器端检查。您在 Go 中设置标头的代码,这就是您需要上面的 JavaScript 的目的。如果您在服务器端设置标头,则根本没有提供任何安全性。这需要在浏览器中发生。如果您将值连同所有请求一起发送,Gorilla 很可能会为您支付其余部分。

    关于问题空间的其他一些随机想法。根据经验,如果攻击者无法重放请求,他们可能无法对您进行 CSRF。这就是为什么这种简单的方法如此有效的原因。每个传入的请求都只有一个需要通过的随机 GUID 值。您可以将该值存储在 cookie 中,因此您不必担心会话跨服务器等移动(如果您不使用双重提交模式,这将需要共享数据存储服务器端;此 cookie-header 值比较业务)。由于当前的硬件限制,这个值没有真正的机会被暴力破解。浏览器中的单一来源策略可防止攻击者读取您设置的 cookie 值(如果设置为安全,则只有您域中的脚本才能访问它)。唯一的利用方法是,如果用户之前曾被 XSS 攻击过,我的意思是,这有点违背了进行 CSRF 的目的,因为攻击者已经拥有更多的控制/能力来使用 XSS 进行恶意操作。

    【讨论】:

    • "如果您在服务器端设置标头,则根本没有提供任何安全性。"不正确 - 它通过与 cookie 相同的通道(应该是 HTTPS)传输,因为 cookie 值也只是一个标头。
    • @elithrar 如果您设置了价值服务器端,那么您根本没有实施任何安全功能。双重提交模式基于这样的想法,即您将给客户端一个只有它可以知道的秘密值。当请求进来时,您将检查该值。这确保了攻击者不能仅仅伪造对您 API 的请求。
    • @elithrar 查看代码,OP 正在设置响应标头。我不确定这是否安全,但我认为这并不重要。约定是将值植入 cookie 中。没有理由将其作为标头,并且鉴于我对标头访问如何由浏览器控制的知识缺乏了解,当安全和/或 httponly cookie 是行业标准时,我不会将其放在那里。服务器将值放入 cookie 中,客户端将其发送到标头中。不要重新发明轮子,它已经是完美的圆形了。
    • 如果你在cookie上设置了HttpOnly,那么客户端就不能访问token来重复提交了。如果你不这样做,那么 cookie 值或响应标头上的 XSS 同样可行 - 例如无论哪种方式,你都被搞砸了!浏览器标头访问在这里不起作用。
    • @elithrar 你说的两件事都是错误的,并在答案中得到了解释。首先,正如我所说,如果你想使用 HttpOnly,那么你需要在 DOM 中写入值,因为 JS 无法访问它。我刚刚在一个 ASP.NET/MVC4 应用程序中做了这个,我知道它是如何工作的,谢谢。其次,cookie 值上的 XSS 是不可行的,它被单一来源策略所阻止,正如我的回答中所解释的那样,如果用户被 XSS 攻击,那么没有理由对它们进行 CSRF,因为你可以只使用 JS您注入以发送您想要的任何请求,它将被验证,因为它在那个上下文中。
    猜你喜欢
    • 2017-11-14
    • 2015-02-08
    • 2021-04-09
    • 2017-03-07
    • 1970-01-01
    • 2015-06-02
    • 2015-10-02
    • 1970-01-01
    • 2017-09-20
    相关资源
    最近更新 更多