CRSF là gì? Phòng chống CRSF với Spring Security

CRSF là gì? Phòng chống CRSF với Spring Security

CRSF là gì?

CSRF hay còn gọi là là “session riding“, “XSRF“, “one-click attack

CSRF ( Cross Site Request Forgery) là kỹ thuật tấn công bằng cách sử dụng quyền chứng thực của người dùng đối với một website. Hiểu một cách nôm na, đây là kỹ thuật tấn công dựa vào mượn quyền trái phép.

Ví dụ, trên trang stackjava.com có một form submit đến máy chủ của trang vietcombank.com.vn. (có thể là click vào một cái ảnh rồi gửi lệnh chuyển tiền tới tài khoản của hacker)

  • Trường hợp người dùng chưa đăng nhập vào trang vietcombank.com.vn: dĩ nhiên khi thực hiện submit nó sẽ thất bại vì request chưa được xác thực.
  • Trường hợp người dùng truy cập cả 2 trang stackjava.comvietcombank.com.vn trên cùng một trình duyệt, sau khi người dùng đăng nhập vào trang vietcombank.com.vn thì trong trình duyệt đã lưu thông tin xác thực (session, cookie hoặc cache…). Bây giờ thực hiện submit form trên trang stackjava.com nó sẽ thực hiện thành công vì đã có thông tin xác thực lấy từ trình duyệt.

Cách phòng chống:

  • Phía server vietcombank.com.vn phải có phương pháp nào đấy để phân biệt được request submit được gửi có đúng là từ trang vietcombank.com.vn không, sử dụng capta, sử dụng method + token phù hợp…
  • Phía người dùng: thoát trang vietcombank.com.vn trước khi truy cập các trang khác…

Phòng chống CRSF với Spring Security

Từ Spring Security 5, chức năng bảo vệ khỏi crsf mặc định được bật, hoặc bạn cũng có thể chỉ rõ bằng thẻ <csrf/> hoặc <csrf disabled="false"/> trong file config spring security. Để tắt crsf ta sử dụng <csrf disabled="true"/>

Cơ chế hoạt bảo vệ crsf trong spring security: mỗi khi nhận một request, spring security sẽ kiểm tra tham số “_csrf” có giá trị đúng với giá trị mà spring security đã khởi tạo cho request nhận được đầu tiên hay không, nếu không có tham số này hoặc giá trị tham số bị sai thì nó sẽ từ chối request.

Để thêm tham số “_csrf” vào request ta thêm tham số sau vào mỗi form:<input type=”hidden” name=”${_csrf.parameterName}” value=”${_csrf.token}” />

CRSF là gì? Phòng chống CRSF với Spring Security stackjava.com

Code ví dụ CRSF trong Spring Security

Các công nghệ sử dụng:

CRSF là gì? Phòng chống CRSF với Spring Security

File Cấu hình Spring Security:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

  <http auto-config="true">
    <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
    <form-login
        login-page="/login"
        login-processing-url="/j_spring_security_login"
        default-target-url="/admin"
      authentication-failure-url="/login?error"
      username-parameter="username"
      password-parameter="password" />
    <logout logout-url="/j_spring_security_logout"
      logout-success-url="/logout" delete-cookies="JSESSIONID" />
    
    <csrf/>			
  </http>

  <authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="admin" password="{noop}123456" authorities="ROLE_ADMIN" />
      </user-service>
    </authentication-provider>
  </authentication-manager>
</beans:beans>

File Controller:

package stackjava.com.springsecurityformlogin.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class BaseController {

  @RequestMapping(value = { "/login", "/" })
  public String login(@RequestParam(value = "error", required = false) final String error, final Model model) {
    if (error != null) {
      model.addAttribute("message", "Login Failed!");
    }
    return "login";
  }

  @RequestMapping("/admin")
  public String admin() {
    return "admin";
  }

  @RequestMapping("/logout")
  public String logout(final Model model) {
    model.addAttribute("message", "Logged out!");
    return "login";
  }

  @RequestMapping("/demo1")
  public String demo1() {
    return "demo1";
  }

  @RequestMapping("/demo2")
  public String demo2() {
    return "demo2";
  }

}

File view:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>login</title>
</head>
<body>
  <h1>Spring MVC-Security Login Form</h1>
  <h2>${message}</h2>

  <form name='loginForm' action="<c:url value='j_spring_security_login' />" method='POST'>
    <table>
      <tr>
        <td>User:</td>
        <td><input type='text' name='username'></td>
      </tr>
      <tr>
        <td>Password:</td>
        <td><input type='password' name='password' /></td>
      </tr>
      <tr>
        <td colspan='2'><input name="submit" type="submit" value="login" /></td>
      </tr>
    </table>
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

  </form>
</body>
</html>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Admin Page</title>
</head>
<body>
  <h1>Admin Page</h1>
  <h2>Welcome: ${pageContext.request.userPrincipal.name}</h2>

  <form action="<c:url value="/j_spring_security_logout" />" method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <input type="submit" value="Logout" />
  </form>

  <form action="<c:url value="/demo1" />" method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <input type="submit" value="Goto Demo Page1" />
  </form>

  <form action="<c:url value="/demo2" />" method="post">
    <input type="submit" value="Goto Demo Page2" />
  </form>

</body>
</html>
<html>
<head>
<title>Demo Page1</title>
</head>
<body>
  <h1>Demo Page1</h1>
</body>
</html>
<html>
<head>
<title>Demo Page 2</title>
</head>
<body>
  <h1>Demo Page 2</h1>
</body>
</html>

Demo:

Đăng nhập với tài khoản admin/123456

CRSF là gì? Phòng chống CRSF với Spring Security

Form logout và demo1 có chứa trường <input type=”hidden” name=”${_csrf.parameterName}” value=”${_csrf.token}” /> nên khi generate ra html nó sẽ có trường”_crsf

CRSF là gì? Phòng chống CRSF với Spring Security

Truy cập trang demo1.jsp (submit form demo1)

CRSF là gì? Phòng chống CRSF với Spring Security

Truy cập trang demo2.jsp (submit form demo2) bị lỗi vì nó không có trường “_crsf

CRSF là gì? Phòng chống CRSF với Spring Security

Để truy cập trang demo2.jsp bạn phải thêm <input type=”hidden” name=”${_csrf.parameterName}” value=”${_csrf.token}” /> vào form demo2 hoặc tắt crsf bằng thẻ <csrf disabled="true"/>

CRSF là gì? Phòng chống CRSF với Spring Security stackjava.com

Okay, Done!

Download code ví dụ trên tại đây

 

Referneces:

https://en.wikipedia.org/wiki/Cross-site_request_forgery

https://viblo.asia/p/ky-thuat-tan-cong-csrf-va-cach-phong-chong-amoG84bOGz8P

stackjava.com