具有 AngularJS 的大猩猩 CSRF
Gorilla CSRF with AngularJS
我正在尝试让 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
您的问题可能有点宽泛,但总的来说您滥用了这些工具,所以我将尝试解释基本概念。您正在使用的应用程序使用 'double submit' 模式来保护 CSRF。这需要更改客户端和服务器代码库。服务器不应该设置X-CSRF-Token
header,那是客户端的作用。实际上,我最近从头开始实施了几个 anti-CSRF 解决方案,它们非常简单(都是双提交模式)。我还使用了 MSTF 和 Apache 等供应商提供的一些软件包(必须在 20 年的各种堆栈上的应用程序中实施 CSRF)。
在双重提交模式中,服务器应设置一个具有随机值的 cookie(如 guid),该 cookie 必须标记为安全。您也可以将其设置为 httponly,但是这需要您在前端资源上做更多的工作。在客户端,处理这个问题的最简单方法是实现一些 JavaScript 来读取 cookie 值并将其作为 header 添加到任何 POST 请求之前。您通常不需要保护 GET。你可以,但是如果你的 GET 正在服务器端做 constructive/destructive 事情,那么你就是在滥用 HTTP 动词,我会通过发出这些请求 POSTS 而不是试图保护每个请求来纠正它。
在服务器端,最好在所有请求进入的公共位置预先进行 CSRF 检查。当 POST 进入时,服务器应读取 cookie 值,检查header 值并比较它们。如果它们相等,那么应该允许请求通过,如果它们不相等,那么您应该使用 403 或其他方式将它们引导出去。这样做之后,服务器应该重写 cookie 值(最好只用一次)。
您的客户端脚本可以包含类似于下面的代码,只需确保资源在每次页面加载时都存在并且您不使用表单提交,这将涵盖所有内容。如果您提交表单,您将需要像这样的一些其他代码来处理它。有些方法更喜欢在 DOM 服务器端写入值。例如,在 .NET 中,CSRF 库将值设为 HTTPOnly 和 Secure,并期望开发人员在他们项目中的每个 cshtml 文件的每个表单中放置一个占位符令牌……我个人认为这是非常愚蠢和低效的。无论如何,您可能都需要做一些定制工作。 Angular 不会为大猩猩 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 中设置 header 的代码,就是你需要上面的 JavaScript 的代码。如果您在服务器端设置 header,则您根本没有提供任何安全措施。这需要在浏览器中发生。如果您将值与所有请求一起发送,Gorilla 很可能会为您支付其余部分。
关于这个问题的一些其他随机想法 space。根据经验,如果攻击者无法重放请求,他们可能无法对您进行 CSRF。这就是为什么这个简单的方法如此有效的原因。每个传入请求都有一个随机 GUID 值,它需要通过该值。您可以将该值存储在 cookie 中,这样您就不必担心 session 在服务器之间移动等(如果您不使用双重提交模式,这将需要共享数据存储服务器端;这 cookie-header价值比较业务)。由于当前的硬件限制,这个值不可能被强制使用。浏览器中的单源策略可防止攻击者读取您设置的 cookie 值(如果设置为安全,则只有来自您域的脚本才能访问它)。唯一利用它的方法是如果用户之前被 XSS 利用过,我的意思是,这有点违背了执行 CSRF 的目的,因为攻击者已经有更多 control/ability 来使用 XSS 做恶意事情。
我正在尝试让 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
您的问题可能有点宽泛,但总的来说您滥用了这些工具,所以我将尝试解释基本概念。您正在使用的应用程序使用 'double submit' 模式来保护 CSRF。这需要更改客户端和服务器代码库。服务器不应该设置X-CSRF-Token
header,那是客户端的作用。实际上,我最近从头开始实施了几个 anti-CSRF 解决方案,它们非常简单(都是双提交模式)。我还使用了 MSTF 和 Apache 等供应商提供的一些软件包(必须在 20 年的各种堆栈上的应用程序中实施 CSRF)。
在双重提交模式中,服务器应设置一个具有随机值的 cookie(如 guid),该 cookie 必须标记为安全。您也可以将其设置为 httponly,但是这需要您在前端资源上做更多的工作。在客户端,处理这个问题的最简单方法是实现一些 JavaScript 来读取 cookie 值并将其作为 header 添加到任何 POST 请求之前。您通常不需要保护 GET。你可以,但是如果你的 GET 正在服务器端做 constructive/destructive 事情,那么你就是在滥用 HTTP 动词,我会通过发出这些请求 POSTS 而不是试图保护每个请求来纠正它。
在服务器端,最好在所有请求进入的公共位置预先进行 CSRF 检查。当 POST 进入时,服务器应读取 cookie 值,检查header 值并比较它们。如果它们相等,那么应该允许请求通过,如果它们不相等,那么您应该使用 403 或其他方式将它们引导出去。这样做之后,服务器应该重写 cookie 值(最好只用一次)。
您的客户端脚本可以包含类似于下面的代码,只需确保资源在每次页面加载时都存在并且您不使用表单提交,这将涵盖所有内容。如果您提交表单,您将需要像这样的一些其他代码来处理它。有些方法更喜欢在 DOM 服务器端写入值。例如,在 .NET 中,CSRF 库将值设为 HTTPOnly 和 Secure,并期望开发人员在他们项目中的每个 cshtml 文件的每个表单中放置一个占位符令牌……我个人认为这是非常愚蠢和低效的。无论如何,您可能都需要做一些定制工作。 Angular 不会为大猩猩 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 中设置 header 的代码,就是你需要上面的 JavaScript 的代码。如果您在服务器端设置 header,则您根本没有提供任何安全措施。这需要在浏览器中发生。如果您将值与所有请求一起发送,Gorilla 很可能会为您支付其余部分。
关于这个问题的一些其他随机想法 space。根据经验,如果攻击者无法重放请求,他们可能无法对您进行 CSRF。这就是为什么这个简单的方法如此有效的原因。每个传入请求都有一个随机 GUID 值,它需要通过该值。您可以将该值存储在 cookie 中,这样您就不必担心 session 在服务器之间移动等(如果您不使用双重提交模式,这将需要共享数据存储服务器端;这 cookie-header价值比较业务)。由于当前的硬件限制,这个值不可能被强制使用。浏览器中的单源策略可防止攻击者读取您设置的 cookie 值(如果设置为安全,则只有来自您域的脚本才能访问它)。唯一利用它的方法是如果用户之前被 XSS 利用过,我的意思是,这有点违背了执行 CSRF 的目的,因为攻击者已经有更多 control/ability 来使用 XSS 做恶意事情。