您的问题可能有点宽泛,但总体而言您滥用了这些工具,因此我将尝试解释基本思想。您正在使用的应用程序使用“双重提交”模式进行 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 进行恶意操作。