使用 X-XSRF-TOKEN(如 angularjs)标头确保 CSRF 保护
Posted
技术标签:
【中文标题】使用 X-XSRF-TOKEN(如 angularjs)标头确保 CSRF 保护【英文标题】:Restassured CSRF protection with X-XSRF-TOKEN (like angularjs) header 【发布时间】:2015-09-13 08:05:47 【问题描述】:我正在尝试编写一个带有放心的 Spring 安全身份验证的 Web 集成测试。该应用程序使用 AngularJS 和 Spring Boot。 由于我使用 AngularJS,CSRF 保护是通过 X-XSRF-TOKEN 标头和 XSRF-TOKEN cookie 完成的(据我所知,它是 angular 的默认值)。
如何配置 reassured 以生成并使用表单身份验证发送此令牌?现在我有这样的东西:
given().auth().form("user", "password", new FormAuthConfig("login", "username", "password").sendCsrfTokenAsHeader()).when().get("/index.html").then().log().all().statusCode(200);
但在日志中,我看到将凭据发布到 /login 时 CSRF 令牌无效。
【问题讨论】:
这可能是一个错误,你有我可以试用的示例服务吗? RESTAssured and WebDriver: get and use a session id from browser的可能重复 我不认为这是重复的。到目前为止,我也有同样的问题,做了很多徒劳的修修补补。 【参考方案1】:在需要时使用 RestAssured 过滤器检索和注入令牌。
鉴于服务器对GET /login
的响应始终包含令牌cookie。那么保持实际测试代码干净的解决方案可能如下所示:
package com.example;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import io.restassured.RestAssured;
import io.restassured.authentication.FormAuthConfig;
import io.restassured.filter.*;
import io.restassured.response.Response;
import io.restassured.specification.*;
@ExtendWith(SpringExtension.class)
@TestInstance(PER_CLASS)
@SpringBootTest(webEnvironment = DEFINED_PORT)
public class CsrfSampleTest
@BeforeAll
public void addCsrfCookieFilter()
RestAssured.filters(new Filter()
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec, FilterContext ctx)
String csrfToken = requestSpec.getCookies().getValue("XSRF-TOKEN");
if (csrfToken == null)
csrfToken = RestAssured.given().noFilters().get("/login").cookie("XSRF-TOKEN");
requestSpec.replaceHeader("X-XSRF-TOKEN", csrfToken);
return ctx.next(requestSpec, responseSpec);
);
@Test
public void test()
RestAssured.given()
.auth().form("user", "password", new FormAuthConfig("login", "username", "password"))
.when()
.get("/index.html")
.then()
.statusCode(200);
【讨论】:
【参考方案2】:您需要在发布前执行 2 GET
才能在您的休息客户端和测试类中使用 Spring Security CSRF 保护。
-
发出
GET
请求登录。这将返回 JSESSIONID
令牌和 XSRF-TOKEN
令牌。如果你使用返回的XSRF-TOKEN
到POST
会失败,因为我们使用空/假JSESSIONID
得到它。
使用上一个请求中的JSESSIONID
,从第二个GET
中获取有用的XSRF-TOKEN
。
现在您可以将XSRF-TOKEN
用作您的POST
。
示例如何使用 CSRF 保护与X-XSRF-TOKEN
放心:
//1) get sessionId
Response response =
given().auth().preemptive().basic(userName, userPassword).contentType(JSON).
when().get(PREFIX_URL + "/users/user").
then().log().all().extract().response();
String jsessionidId = response.getSessionId();//or response.cookie("JSESSIONID");
//2) get XSRF-TOKEN using new/real sessionId
response =
given().
sessionId(jsessionidId).//or cookie("JSESSIONID", jsessionidId).
contentType(JSON).
when().get(PREFIX_URL + "/users/user").
then().log().all().extract().response();
//3) post data using XSRF-TOKEN
given().log().all().
sessionId(jsessionidId).//or cookie("JSESSIONID", jsessionidId).
header("X-XSRF-TOKEN", response.cookie("XSRF-TOKEN")).
queryParam("pos",pos.getId()).
queryParam("date",date).
queryParam("group_id",itemGroup.getId()).
body(orderItems).
contentType(JSON).
when().
post(PREFIX_URL + "/orders/orderitems").
then().
log().all().assertThat().statusCode(200);
【讨论】:
这里它要求表单参数而不是基本自动。在您的示例中,您使用的是基本身份验证,但上述问题需要表单参数。【参考方案3】:回复有些延迟,但我希望它可以帮助某人
Response loginResponse = given().contentType(APPLICATION_JSON).
param(USERNAME, "").
param(PASSWORD, "").
when().post(LOGIN_PROCESSING_URL).then().log().all().
extract().response();
given().contentType(APPLICATION_JSON).
cookie("XSRF-TOKEN", loginResponse.cookie("XSRF-TOKEN")).
header("X-XSRF-TOKEN", loginResponse.cookie("XSRF-TOKEN")).
sessionId(loginResponse.getSessionId()).
when().post(USER_PATH).
then().log().all().statusCode(CREATED.value());
【讨论】:
以上是关于使用 X-XSRF-TOKEN(如 angularjs)标头确保 CSRF 保护的主要内容,如果未能解决你的问题,请参考以下文章
Angular 6 不会将 X-XSRF-TOKEN 标头添加到 http 请求
标头 Laravel 5.3 + Angular2 中不允许 X-XSRF-TOKEN
使用 X-XSRF-TOKEN(如 angularjs)标头确保 CSRF 保护