使用X-XSRF-TOKEN(如angularjs)标头重新确保CSRF保护

时间:2015-06-26 11:24:17

标签: angularjs spring-security csrf rest-assured

我正在尝试使用重新安全的Spring安全身份验证编写Web集成测试。该应用程序使用AngularJS和Spring Boot。 由于我使用AngularJS,CSRF保护是通过X-XSRF-TOKEN标头和XSRF-TOKEN cookie完成的(据我所知,它是角度的默认值)。

如何将restassured配置为生成并使用表单身份验证发送此令牌?现在我有这样的事情:

given().auth().form("user", "password", new FormAuthConfig("login", "username", "password").sendCsrfTokenAsHeader()).when().get("/index.html").then().log().all().statusCode(200);

但是在日志中,我发现将凭据发布到/ login时,CSRF令牌无效。

3 个答案:

答案 0 :(得分:2)

您需要在发布之前执行2 GET以在您的其他客户端和测试类中使用spring security CSRF保护。

  1. 发出GET个登录请求。这将返回JSESSIONID令牌和XSRF-TOKEN令牌。如果您使用返回的XSRF-TOKENPOST,则会失败,因为我们使用空/假JSESSIONID来获取它。
  2. 使用先前请求中的XSRF-TOKEN从第二个GET获取有用的JSESSIONID
  3. 现在,您可以XSRF-TOKEN使用POST
  4. 如何在X-XSRF-TOKEN放心使用CSRF保护的示例:

    //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);
    

答案 1 :(得分:1)

有些延迟回应,但我希望它可以帮助某人

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());

答案 2 :(得分:0)

在需要时使用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);
    }
}