Ответ 1
Моя проблема заключалась в том, что я не хотел использовать MVC и просто обслуживал статические html файлы, поддерживаемые WebApi. Вот что я сделал (будет ли это работать?) Создайте модуль Http, который устанавливает случайное значение cookie при обслуживании любого статического файла. Например:
public class XSRFModule : IHttpModule {
...
void context_EndRequest(object sender, EventArgs e) {
if (Path.GetExtension(HttpContext.Current.Request.Path) == ".html") {
HttpContext.Current.Response.Cookies.Add(new HttpCookie("XSRF-TOKEN", Guid.NewGuid().ToString()));
}
}
}
Затем на странице html используйте javascript для добавления значения cookie в заголовок при вызове api:
function callApi() {
xhr = new XMLHttpRequest();
xhr.open("GET", "api/data", true);
var regex = /\b(?:XSRF-TOKEN=)(.*?)(?=\s|$)/
var match = regex.exec(document.cookie);
xhr.setRequestHeader("X-XSRF-TOKEN", match[1]);
xhr.send();
}
Наконец, в HttpModule
убедитесь, что cookie соответствует заголовку перед обработкой любых вызовов на ваш api:
void context_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.Path.StartsWith("/api"))
{
string fromCookie = HttpContext.Current.Request.Cookies.Get("XSRF-TOKEN").Value;
string fromHeader = HttpContext.Current.Request.Headers["X-XSRF-TOKEN"];
if (fromCookie != fromHeader)
{
HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.Forbidden;
HttpContext.Current.Response.End();
}
}
}
Вам нужно установить флаг HttpOnly
на FALSE
, чтобы javascript из вашего домена мог прочитать cookie и установить заголовок. Я не эксперт по безопасности, поэтому мне хотелось бы получить некоторые отзывы об этом решении от некоторых других членов сообщества.
ИЗМЕНИТЬ
Если вы используете OWIN, вы можете использовать глобальный фильтр действий вместе с плагином промежуточного программного обеспечения:
Startup.cs
app.UseStaticFiles(new StaticFileOptions {
OnPrepareResponse = (responseContext) => {
responseContext.OwinContext.Response.Cookies.Append("XSRF-TOKEN", Guid.NewGuid().ToString());
},
FileSystem = "wwwroot"
});
XsrfFilter.cs
public class XsrfFilter : ActionFilterAttribute {
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) {
string fromCookie = actionContext.Request.Headers.GetCookies("XSRF-TOKEN").FirstOrDefault()["XSRF-TOKEN"].Value;
string fromHeader = actionContext.Request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault();
if (fromCookie == fromHeader) return;
actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK);
actionContext.Response.ReasonPhrase = "bad request";
}
}