在任何VM中部署时,令牌不匹配异常

发布于 2025-02-11 00:03:44 字数 4594 浏览 1 评论 0原文

这是我的CSRF和CORS处理程序,

@Log4j2
public class CsrfVerticle extends AbstractVerticle {

  private final Set<HttpMethod> httpMethodSet =
      new HashSet<>(Arrays.asList(GET, POST, OPTIONS, PUT, DELETE, HEAD));
  private final Set<String> headerSet = new HashSet<>(
      Arrays.asList("Content-Type", "Authorization", "Origin", "Accept", "X-Requested-With",
          "Cookie", "X-XSRF-TOKEN"));
  private Connection dbConnection;
  private WebClient webClient;
  private Vertx vertx;

  public void start() throws Exception {
    super.start();
    HttpServer httpServer = TestService.vertx.createHttpServer();
    Router router = Router.router(TestService.vertx);
    SessionStore store = LocalSessionStore.create(vertx);

    SessionHandler sessionHandler = SessionHandler.create(store)
        .setCookieSameSite(CookieSameSite.STRICT)
        .setCookieHttpOnlyFlag(false);
    router.route().handler(LoggerHandler.create());
    if (TestService.serviceConfiguration.isEnableCSRF()) {
      router.route()
          .handler(CorsHandler.create("*").allowedMethods(httpMethodSet).allowedHeaders(headerSet)
              .allowCredentials(true).addOrigin(TestService.serviceConfiguration.getFrontendUrl()));
      router.route().handler(
              CSRFHandler.create(vertx, csrfSecret()).setCookieHttpOnly(false))
          .handler(sessionHandler);
    } else {

      router.route()
          .handler(CorsHandler.create("*").allowedMethods(httpMethodSet).allowedHeaders(headerSet)
              .allowCredentials(true)).handler(sessionHandler);
    }
    dbConnection = createConnection(TestService.serviceConfiguration.getJdbcConfig());
    TestAuth testAuth = new TestAuth(TestService.serviceConfiguration.getUsername(),
        TestService.serviceConfiguration.getPassword());
    AuthenticationHandler basicAuthHandler = BasicAuthHandler.create(testAuth);
    router.route("/student/*").handler(basicAuthHandler);

    router.route("/student/add").method(HttpMethod.POST).handler(this::handleAddUser);
    router.route("/student/get").method(HttpMethod.GET).handler(this::handleGetUser);
    router.route("/student/delete").method(HttpMethod.DELETE)
        .handler(this::handleDeleteUser);
    router.route("/student/update").method(HttpMethod.PUT).handler(this::handleUpdateUser);

    httpServer.requestHandler(router).listen(TestService.serviceConfiguration.getPort());
    log.info("Console Server Verticle Started Successfully. Listening to {} port",
        TestService.serviceConfiguration.getPort());
  }

我可以在浏览器中接收cookie,并将其与已更新的X-xsrf-toke一起发送回标题,并将其附加到标题上,

一切都在我的本地中工作正常,但是当在VM中部署时,我会得到以下内容。所有发布请求的错误 ctx.fail(403,新的IllegalargumentException(“令牌签名不匹配”)); 来自VERTX的CSRF处理程序。

是将请求发送到后端时添加X-XSRF的前端代码

createXsrfHeader(headers: HttpHeaders) {
    let xsrfToken = Cookies.get('XSRF-TOKEN')
    let sessionToken = Cookies.get('vertx-web.session')

    if(xsrfToken)
       headers = headers.append('X-XSRF-TOKEN', xsrfToken);

    // if(xsrfToken && sessionToken)
    //    headers = headers.append('Cookie', `XSRF-TOKEN=${xsrfToken}; vertx-web.session=${sessionToken}`);
    

    return headers;
 }

[将标题添加到发布请求]

callPostRequest(subUrl: string,reqData: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.post<any>(this.basicApiUrl+subUrl, reqData, {
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

[添加标头以

callPutRequest(subUrl: string,reqData: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.put<any>(this.basicApiUrl+subUrl, reqData,{
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

放置请求]

callDeleteRequest(subUrl: string,reqData?: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.delete<any>(this.basicApiUrl+subUrl, {
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

以下

Here is my csrf and cors handler of my vertx application

@Log4j2
public class CsrfVerticle extends AbstractVerticle {

  private final Set<HttpMethod> httpMethodSet =
      new HashSet<>(Arrays.asList(GET, POST, OPTIONS, PUT, DELETE, HEAD));
  private final Set<String> headerSet = new HashSet<>(
      Arrays.asList("Content-Type", "Authorization", "Origin", "Accept", "X-Requested-With",
          "Cookie", "X-XSRF-TOKEN"));
  private Connection dbConnection;
  private WebClient webClient;
  private Vertx vertx;

  public void start() throws Exception {
    super.start();
    HttpServer httpServer = TestService.vertx.createHttpServer();
    Router router = Router.router(TestService.vertx);
    SessionStore store = LocalSessionStore.create(vertx);

    SessionHandler sessionHandler = SessionHandler.create(store)
        .setCookieSameSite(CookieSameSite.STRICT)
        .setCookieHttpOnlyFlag(false);
    router.route().handler(LoggerHandler.create());
    if (TestService.serviceConfiguration.isEnableCSRF()) {
      router.route()
          .handler(CorsHandler.create("*").allowedMethods(httpMethodSet).allowedHeaders(headerSet)
              .allowCredentials(true).addOrigin(TestService.serviceConfiguration.getFrontendUrl()));
      router.route().handler(
              CSRFHandler.create(vertx, csrfSecret()).setCookieHttpOnly(false))
          .handler(sessionHandler);
    } else {

      router.route()
          .handler(CorsHandler.create("*").allowedMethods(httpMethodSet).allowedHeaders(headerSet)
              .allowCredentials(true)).handler(sessionHandler);
    }
    dbConnection = createConnection(TestService.serviceConfiguration.getJdbcConfig());
    TestAuth testAuth = new TestAuth(TestService.serviceConfiguration.getUsername(),
        TestService.serviceConfiguration.getPassword());
    AuthenticationHandler basicAuthHandler = BasicAuthHandler.create(testAuth);
    router.route("/student/*").handler(basicAuthHandler);

    router.route("/student/add").method(HttpMethod.POST).handler(this::handleAddUser);
    router.route("/student/get").method(HttpMethod.GET).handler(this::handleGetUser);
    router.route("/student/delete").method(HttpMethod.DELETE)
        .handler(this::handleDeleteUser);
    router.route("/student/update").method(HttpMethod.PUT).handler(this::handleUpdateUser);

    httpServer.requestHandler(router).listen(TestService.serviceConfiguration.getPort());
    log.info("Console Server Verticle Started Successfully. Listening to {} port",
        TestService.serviceConfiguration.getPort());
  }

I am able to receive cookies in browser and send it back along with updated X-XSRF-TOKEN attached to the header

Everything works fine in my local but when deploying in VM I get the below error for all post requests
ctx.fail(403, new IllegalArgumentException("Token signature does not match"));
from csrf handler of vertx.

Here are the frontend code to add x-xsrf-token when sending requests to backend

createXsrfHeader(headers: HttpHeaders) {
    let xsrfToken = Cookies.get('XSRF-TOKEN')
    let sessionToken = Cookies.get('vertx-web.session')

    if(xsrfToken)
       headers = headers.append('X-XSRF-TOKEN', xsrfToken);

    // if(xsrfToken && sessionToken)
    //    headers = headers.append('Cookie', `XSRF-TOKEN=${xsrfToken}; vertx-web.session=${sessionToken}`);
    

    return headers;
 }

[Adding header to post request]

callPostRequest(subUrl: string,reqData: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.post<any>(this.basicApiUrl+subUrl, reqData, {
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

[Adding header to put request]

callPutRequest(subUrl: string,reqData: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.put<any>(this.basicApiUrl+subUrl, reqData,{
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

[Adding header to delete request]

callDeleteRequest(subUrl: string,reqData?: any) {
    let headers = new HttpHeaders();
    headers = this.createAuthorizationHeader(headers);
    headers = this.createXsrfHeader(headers);
    return this.http.delete<any>(this.basicApiUrl+subUrl, {
      headers: headers,
      withCredentials : true
    }).pipe(map(resData => {
        // console.log(resData);
        return resData;
      }));
  }

Is there any ways to solve it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

反差帅 2025-02-18 00:03:46

我相信您的问题在这里:

router.route() // <--- HERE
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
      .handler(sessionHandler);

您正在告诉应用程序,以创建一个新的csrf令牌,为每个正在发生的请求创建,而不是具体说明哪些端点实际上是基于表单的端点。

想象以下内容,您的表格在/student/form您的浏览器可能请求:

/student/form (new CSRF token: OK)
/images/some-image-in-the-html.png  (new CSRF token: probably Wrong)
/css/styles.css  (new CSRF token: probably Wrong)
...

现在问题是第一个呼叫确实正确地生成了令牌,但是以下2+也会生成新的令牌,并且这些不匹配第一个,因此您的令牌始终被未对准。

您可能需要从要保护的资源中更具体地说,从您的代码中,我假设您可能想要类似的东西:

router.route(""/student/*") // <--- Froms are always here under
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
      .handler(sessionHandler);

如果调用其他端点也会影响表格,请小心。请注意,您可以每条路线添加多个处理程序,因此您可以更明确地说:

router.route(""/student/add")
  // 1st always CSRF checks
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
  // and now we the handler that will handle the form data
  .handler(this::handleAddUser)

I believe your problem is here:

router.route() // <--- HERE
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
      .handler(sessionHandler);

You are telling the application to create a new CSRF token for each request that is happening, instead of being specific of which end points are really form-based endpoints.

Imagine the following, your form is on /student/form your browser may request:

/student/form (new CSRF token: OK)
/images/some-image-in-the-html.png  (new CSRF token: probably Wrong)
/css/styles.css  (new CSRF token: probably Wrong)
...

Now the issue is that the 1st call did correctly generated a token, but the following 2+ will generate new tokens too and these won't match the 1st so your tokens are always misaligned.

You probably need to be more specific with the resources you want to protect, from your code I am assuming that you probably want something like:

router.route(""/student/*") // <--- Froms are always here under
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
      .handler(sessionHandler);

Be careful if calling other endpoints would affect the forms too. Note that you can add multiple handlers per route, so you can be more explicit with:

router.route(""/student/add")
  // 1st always CSRF checks
  .handler(
    CSRFHandler.create(vertx, csrfSecret())
      .setCookieHttpOnly(false))
  // and now we the handler that will handle the form data
  .handler(this::handleAddUser)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文