dbr*_*ing 69 javascript asp.net csrf asp.net-web-api angularjs
我正在Angular.js中实现一个网站,它正在攻击ASP.NET WebAPI后端.
Angular.js具有一些内置功能,可以帮助防止csrf.在每个http请求中,它将查找名为"XSRF-TOKEN"的cookie并将其作为名为"X-XSRF-TOKEN"的标头提交.
这依赖于Web服务器能够在对用户进行身份验证之后设置XSRF-TOKEN cookie,然后检查X-XSRF-TOKEN标头以获取传入请求.
该角文档状态:
要利用这一点,您的服务器需要在第一个HTTP GET请求中在名为XSRF-TOKEN的JavaScript可读会话cookie中设置令牌.在后续的非GET请求中,服务器可以验证cookie是否与X-XSRF-TOKEN HTTP标头匹配,因此请确保只有您域上运行的JavaScript才能读取令牌.令牌对于每个用户必须是唯一的,并且必须由服务器验证(以防止JavaScript组成自己的令牌).我们建议令牌是您网站的身份验证cookie的摘要,以增加安全性.
我找不到ASP.NET WebAPI的任何好例子,所以我在各种来源的帮助下推出了自己的例子.我的问题是 - 任何人都可以看到代码有什么问题吗?
首先我定义了一个简单的帮助器类:
public class CsrfTokenHelper
{
const string ConstantSalt = "<ARandomString>";
public string GenerateCsrfTokenFromAuthToken(string authToken)
{
return GenerateCookieFriendlyHash(authToken);
}
public bool DoesCsrfTokenMatchAuthToken(string csrfToken, string authToken)
{
return csrfToken == GenerateCookieFriendlyHash(authToken);
}
private static string GenerateCookieFriendlyHash(string authToken)
{
using (var sha = SHA256.Create())
{
var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(authToken + ConstantSalt));
var cookieFriendlyHash = HttpServerUtility.UrlTokenEncode(computedHash);
return cookieFriendlyHash;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在授权控制器中使用以下方法,并在调用FormsAuthentication.SetAuthCookie()后调用它:
// http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks
// http://docs.angularjs.org/api/ng.$http
private void SetCsrfCookie()
{
var authCookie = HttpContext.Current.Response.Cookies.Get(".ASPXAUTH");
Debug.Assert(authCookie != null, "authCookie != null");
var csrfToken = new CsrfTokenHelper().GenerateCsrfTokenFromAuthToken(authCookie.Value);
var csrfCookie = new HttpCookie("XSRF-TOKEN", csrfToken) {HttpOnly = false};
HttpContext.Current.Response.Cookies.Add(csrfCookie);
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个自定义属性,我可以添加到控制器,使他们检查csrf标头:
public class CheckCsrfHeaderAttribute : AuthorizeAttribute
{
// http://stackoverflow.com/questions/11725988/problems-implementing-validatingantiforgerytoken-attribute-for-web-api-with-mvc
protected override bool IsAuthorized(HttpActionContext context)
{
// get auth token from cookie
var authCookie = HttpContext.Current.Request.Cookies[".ASPXAUTH"];
if (authCookie == null) return false;
var authToken = authCookie.Value;
// get csrf token from header
var csrfToken = context.Request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault();
if (String.IsNullOrEmpty(csrfToken)) return false;
// Verify that csrf token was generated from auth token
// Since the csrf token should have gone out as a cookie, only our site should have been able to get it (via javascript) and return it in a header.
// This proves that our site made the request.
return new CsrfTokenHelper().DoesCsrfTokenMatchAuthToken(csrfToken, authToken);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我在用户注销时清除Csrf令牌:
HttpContext.Current.Response.Cookies.Remove("XSRF-TOKEN");
Run Code Online (Sandbox Code Playgroud)
任何人都可以发现任何明显(或不那么明显)的问题吗?
你的代码似乎没问题.唯一的问题是,你不需要你拥有的大部分代码,因为web.api运行在asp.net mvc的"顶部",而后者已经内置了对防伪标记的支持.
在评论中,dbrunning和ccorrin表示担心只有在使用MVC html助手时才能使用AntiForgery令牌中的构建.这不是真的.帮助程序可以公开基于会话的令牌对,您可以相互验证这些令牌.请参阅下文了解详情.
更新:
您可以从AntiForgery中使用两种方法:
AntiForgery.GetTokens 使用两个输出参数来返回cookie令牌和表单令牌
AntiForgery.Validate(cookieToken, formToken) 验证一对令牌是否有效
您完全可以重新调整这两种方法,并将formToken用作headerToken,将cookieToken用作实际的cookieToken.然后只需在属性内调用validate.
另一个解决方案是使用JWT(检查例如MembershipReboot实现)
此链接显示如何使用带有ajax的内置防伪令牌:
<script>
@functions{
public string TokenHeaderValue()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajax("api/values", {
type: "post",
contentType: "application/json",
data: { }, // JSON data goes here
dataType: "json",
headers: {
'RequestVerificationToken': '@TokenHeaderValue()'
}
});
</script>
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
Run Code Online (Sandbox Code Playgroud)
另外看看这个问题AngularJS找不到XSRF-TOKEN cookie
| 归档时间: |
|
| 查看次数: |
14586 次 |
| 最近记录: |