我正在尝试让AngularJS与Gorilla CSRF一起使用我的网络应用程序,但是我找不到很多文档,所以我不确定从哪里开始.我应该X-CSRF-Token
为每个GET
请求设置一个,还是应该在用户访问主页时执行此操作,就像我现在正在做的那样?另外,如何使用Gorilla CSRF使AngularJS 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
evanmcdonnal.. 5
你的问题可能有点广泛,但总的来说你误用了这些工具,所以我只是试着解释基本的想法.您正在使用的应用程序使用"双提交"模式进行CSRF保护.这需要更改客户端和服务器代码库.服务器不应该设置X-CSRF-Token
标头,即客户端的角色.我最近实际上实现了几个从头开始反CSRF解决方案,它们非常简单(都是双提交模式).我还使用了来自MSTF和Apache等供应商的一些软件包(必须在各种堆栈的20年应用程序中实现CSRF).
在双提交模式中,服务器应该设置具有随机值的cookie(如guid),cookie必须标记为安全.您也可以将其设为httponly,但是它需要您在前端资源上做更多的工作.在客户端,处理此问题的最简单方法是实现一些读取cookie值的JavaScript,并在任何POST请求之前将其添加为标头.您通常不需要保护GET.你可以,但是如果你的GET正在服务器方面做建设性/破坏性事情,那么你就是在滥用HTTP动词,我会通过将这些请求发送到POSTS而不是试图保护每一个请求来纠正它.
在服务器端,最好在所有请求进入的公共位置进行CSRF检查.当POST进入时,服务器应读取cookie值,检查标头值并进行比较.如果它们相等则应该允许请求通过,如果它们不是那么你应该用403或者其他东西启动它们.执行此操作后,服务器应重写cookie值(最好只使用一次).
您的客户端脚本可以具有类似下面的代码,只需确保资源在每个页面加载,并且您不使用表单提交,这将涵盖所有内容.如果您提交表单,则需要一些其他代码才能处理.有些方法更喜欢在DOM服务器端编写值.例如在.NET中,CSRF库使值为HTTPOnly和Secure,并期望开发人员在其项目中的每个单独的cshtml文件中的每个表单中放置一个占位符令牌......我个人认为这是非常愚蠢和低效的.不管你怎么做,你可能要做一些定制工作.Angular不会为gorillas CSRF库实现前端.大猩猩可能不会为您的客户端提供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 ""; }
现在,如果你可以稍微缩小你的问题,我可以提供一些更具体的指导,但这只是一个猜测(也许我会在我有一分钟时阅读他们的文档).如果您使用,Gorilla会自动设置您的cookie并为您进行服务器端检查csrf.Protect
.你在Go中设置标题的代码,就是你需要上面的JavaScript.如果在服务器端设置标头,则根本没有提供安全性.这需要在浏览器中进行.如果您将该值与所有请求一起发送,Gorilla很可能会为您提供剩余的请求.
关于问题空间的一些其他随机想法.根据经验,如果攻击者无法重播请求,他们可能无法对您进行CSRF.这就是为什么这种简单方法如此有效.每个传入的请求都只有一个随机的GUID值.您可以将该值存储在cookie中,这样您就不必担心会话跨服务器移动ect(如果您不使用双提交模式,则需要共享数据存储服务器端;此cookie-header值比较业务).在目前的硬件限制下,这个值很难被强行逼迫.浏览器中的单一来源策略可防止攻击者读取您设置的cookie值(如果设置为安全,则只有来自您域的脚本才能访问它).利用这种方法的唯一方法是,如果用户之前已被XSS利用,我的意思是,由于攻击者已经拥有更多的控制/能力来使用XSS进行恶意攻击,因此无法实现CSRF的目的.
你的问题可能有点广泛,但总的来说你误用了这些工具,所以我只是试着解释基本的想法.您正在使用的应用程序使用"双提交"模式进行CSRF保护.这需要更改客户端和服务器代码库.服务器不应该设置X-CSRF-Token
标头,即客户端的角色.我最近实际上实现了几个从头开始反CSRF解决方案,它们非常简单(都是双提交模式).我还使用了来自MSTF和Apache等供应商的一些软件包(必须在各种堆栈的20年应用程序中实现CSRF).
在双提交模式中,服务器应该设置具有随机值的cookie(如guid),cookie必须标记为安全.您也可以将其设为httponly,但是它需要您在前端资源上做更多的工作.在客户端,处理此问题的最简单方法是实现一些读取cookie值的JavaScript,并在任何POST请求之前将其添加为标头.您通常不需要保护GET.你可以,但是如果你的GET正在服务器方面做建设性/破坏性事情,那么你就是在滥用HTTP动词,我会通过将这些请求发送到POSTS而不是试图保护每一个请求来纠正它.
在服务器端,最好在所有请求进入的公共位置进行CSRF检查.当POST进入时,服务器应读取cookie值,检查标头值并进行比较.如果它们相等则应该允许请求通过,如果它们不是那么你应该用403或者其他东西启动它们.执行此操作后,服务器应重写cookie值(最好只使用一次).
您的客户端脚本可以具有类似下面的代码,只需确保资源在每个页面加载,并且您不使用表单提交,这将涵盖所有内容.如果您提交表单,则需要一些其他代码才能处理.有些方法更喜欢在DOM服务器端编写值.例如在.NET中,CSRF库使值为HTTPOnly和Secure,并期望开发人员在其项目中的每个单独的cshtml文件中的每个表单中放置一个占位符令牌......我个人认为这是非常愚蠢和低效的.不管你怎么做,你可能要做一些定制工作.Angular不会为gorillas CSRF库实现前端.大猩猩可能不会为您的客户端提供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 ""; }
现在,如果你可以稍微缩小你的问题,我可以提供一些更具体的指导,但这只是一个猜测(也许我会在我有一分钟时阅读他们的文档).如果您使用,Gorilla会自动设置您的cookie并为您进行服务器端检查csrf.Protect
.你在Go中设置标题的代码,就是你需要上面的JavaScript.如果在服务器端设置标头,则根本没有提供安全性.这需要在浏览器中进行.如果您将该值与所有请求一起发送,Gorilla很可能会为您提供剩余的请求.
关于问题空间的一些其他随机想法.根据经验,如果攻击者无法重播请求,他们可能无法对您进行CSRF.这就是为什么这种简单方法如此有效.每个传入的请求都只有一个随机的GUID值.您可以将该值存储在cookie中,这样您就不必担心会话跨服务器移动ect(如果您不使用双提交模式,则需要共享数据存储服务器端;此cookie-header值比较业务).在目前的硬件限制下,这个值很难被强行逼迫.浏览器中的单一来源策略可防止攻击者读取您设置的cookie值(如果设置为安全,则只有来自您域的脚本才能访问它).利用这种方法的唯一方法是,如果用户之前已被XSS利用,我的意思是,由于攻击者已经拥有更多的控制/能力来使用XSS进行恶意攻击,因此无法实现CSRF的目的.