찾다
Javajava지도 시간CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

CSRF 원리

CSRF 공격을 방어하려면 먼저 CSRF 공격이 무엇인지 이해해야 합니다. 다음 그림을 통해 CSRF 공격 프로세스를 정리하겠습니다.

CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

사실 이 프로세스는 매우 간단합니다:
1. 사용자가 China Merchants Online Banking 웹사이트로 이동하여 로그인한다고 가정합니다.
2. 로그인이 성공하면 온라인 뱅킹은 쿠키를 프런트 엔드로 반환하고 브라우저는 쿠키를 저장합니다.
3. 사용자는 온라인 뱅킹에서 로그아웃하지 않고 브라우저에서 새 탭을 연 후 위험한 웹 사이트를 방문했습니다.
4. 이 위험한 웹사이트에는 하이퍼링크가 있고, 하이퍼링크의 주소는 China Merchants Online Banking을 가리킵니다.
4. 사용자가 이 링크를 클릭하면 브라우저에 저장된 쿠키가 자동으로 전달되므로 사용자가 자신도 모르게 온라인 뱅킹에 접속하여 손해를 입을 수 있습니다.

CSRF의 프로세스는 대략 이렇습니다. 다음으로 간단한 예를 사용하여 CSRF가 무엇인지 보여드리겠습니다.

CSRF practice

1. 저는 csrf-mry라는 이름의 Spring Boot 프로젝트를 만들었습니다. 이 프로젝트는 위에서 언급한 온라인 뱅킹 웹사이트와 동일하며, 다음과 같이 웹 및 Spring 보안 종속성을 도입했습니다.

2 생성이 성공한 후 편의를 위해 application.properties 파일에서 Spring Security 사용자 이름/비밀번호를 직접 구성합니다.

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

3 그런 다음 /transfer가 전송 인터페이스라고 가정하여 두 개의 테스트 인터페이스

server.port= 8866
spring.security.user.name=javaboy
spring.security.user.password=123

를 제공합니다( 여기가 주로 모든 사람에게 CSRF 공격을 시연하는 것이라고 가정하면 실제 전송 인터페이스는 이보다 더 복잡합니다.

4. Spring Security는 기본적으로 CSRF 공격을 자동으로 방어할 수 있으므로 Spring Security도 구성해야 합니다. 따라서 이 기능을 꺼야 합니다.

package com.mry.csrf.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CsrfDemoController {
    @PostMapping("/transfer")
    public void transferMoney(String name, Integer money) {
        System.out.println("name = " + name);
        System.out.println("money = " + money);
    }
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

구성이 완료되면 csrf-simulate-web 프로젝트를 시작합니다.

5. 또 다른 csrf-loophole-web 프로젝트를 생성해 보겠습니다. 이 프로젝트는 편의상 여기서 생성할 때 웹 종속성만 도입하면 됩니다.

프로젝트가 성공적으로 생성된 후 먼저 프로젝트 포트를 수정합니다:

package com.mry.csrf.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .csrf()
                .disable();
    }
}

6. 그런 다음 resources/static 디렉토리에 다음 내용으로 hello.html을 생성합니다.

server.port= 8855

여기에 하이퍼링크가 있습니다. 하이퍼링크의 텍스트를 클릭하면 아름다운 여성의 사진을 볼 수 있습니다. 하이퍼링크를 클릭하면 자동으로 http://localhost:8866/transfer 인터페이스가 요청됩니다. 시간이 지나면 숨겨진 도메인에도 두 개의 매개변수가 있습니다.

구성이 완료되면 csrf-loophole-web 프로젝트를 시작할 수 있습니다.

다음으로 사용자는 먼저 csrf-simulate-web 프로젝트의 인터페이스에 액세스해야 하며, 액세스가 완료된 후 사용자는 로그인 작업을 수행하지 않습니다. , 그리고 사용자는 csrf-loophole에 액세스합니다. - 웹 페이지에서 하이퍼링크를 보고 이 아름다움이 어떻게 생겼는지 궁금해서 클릭하자마자 돈이 이체되었습니다.

CSRF Defense

먼저 방어 아이디어에 대해 이야기해 보겠습니다.

CSRF 방어의 핵심 아이디어는 프런트 엔드 요청에 임의의 숫자를 추가하는 것입니다.

CSRF 공격에서는 해커 웹사이트가 실제로 사용자의 쿠키가 무엇인지 알지 못하기 때문에 사용자가 직접 온라인 뱅킹 웹사이트에 요청을 보낼 수 있습니다. 이 프로세스가 자동으로 쿠키에 있는 정보를 전달하기 때문입니다.

그래서 우리의 방어 아이디어는 다음과 같습니다. 사용자가 온라인 뱅킹에 액세스할 때 쿠키에 정보를 전달하는 것 외에도 사용자가 이 난수를 가지고 있지 않으면 온라인 뱅킹 웹사이트가 임의의 숫자를 가지고 있어야 합니다. 요청을 거부합니다. 해커 웹사이트가 사용자에게 하이퍼링크를 클릭하도록 유도하면 쿠키에 자동으로 정보가 전달되지만 난수는 자동으로 전달되지 않으므로 CSRF 공격을 성공적으로 피할 수 있습니다.

Spring Security는 이에 대한 좋은 지원을 제공합니다. 살펴보겠습니다.

백엔드와 백엔드 비분리 솔루션

Spring Security는 실제로 기본적으로 CSRF 방어를 제공하지만 개발자가 더 많은 작업을 수행해야 합니다.

먼저 새로운 Spring Boot 프로젝트를 생성하고 이를 생성할 때 Spring Security, Thymeleaf 및 웹 종속성을 도입합니다.

1.pom 정보

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="http://localhost:8866/transfer" method="post">
        <input type="hidden" value="javaboy" name="name">
        <input type="hidden" value="10000" name="money">
        <input type="submit" value="点击查看美女图片">
    </form>
</body>
</html>

2. 프로젝트가 성공적으로 생성된 후에도 application.properties

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

3에서 사용자 이름/비밀번호를 구성합니다. 다음으로 테스트 인터페이스를 제공합니다

spring.security.user.name=mry
spring.security.user.password=123456

이 테스트 인터페이스는 다음과 같습니다. POST 요청. 기본적으로 GET, HEAD, TRACE 및 OPTIONS에는 CSRF 공격에 대한 확인이 필요하지 않기 때문입니다.

4. 그런 다음 resources/templates 디렉토리에 새로운 thymeleaf 템플릿을 생성합니다

package com.mry.csrf.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SecurityCsrfController {
    @PostMapping("/hello")
    @ResponseBody
    public String hello() {
        return "hello";
    }
}

POST 요청을 보낼 때 숨겨진 필드의 키는 ${_csrf.parameterName}입니다. 값은 ${_csrf.token}입니다.

서버는 자동으로 이 두 값을 가져오므로 프런트 엔드에서만 렌더링하면 됩니다.

5. 다음으로 프런트엔드 hello.html 페이지에 컨트롤러를 추가합니다.

<!DOCTYPE html>
<!--导入thymeleaf的名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/hello" method="post">
        <input type="hidden" th:value="${_csrf.token}" th:name="${_csrf.parameterName}">
        <input type="submit" value="hello">
    </form>
</body>
</html>

6. 추가가 완료되면 프로젝트를 시작하고, 접속 시 먼저 로그인을 해야 합니다. 로그인이 성공하면 로그인을 볼 수 있습니다. 요청에 추가 매개변수도 있습니다

CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

这里我们用了 Spring Security 的默认登录页面,如果大家使用自定义登录页面,可以参考上面 hello.html 的写法,通过一个隐藏域传递 _csrf 参数。

访问到 hello 页面之后,再去点击【hello】按钮,就可以访问到 hello 接口了。

CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

这是 Spring Security 中默认的方案,通过 Model 将相关的数据带到前端来。

如果你的项目是前后端不分项目,这种方案就可以了,如果你的项目是前后端分离项目,这种方案很明显不够用。

前后端分离方案

如果是前后端分离项目,Spring Security 也提供了解决方案。
这次不是将 _csrf 放在 Model 中返回前端了,而是放在 Cookie 中返回前端,配置方式如下:

package com.mry.csrf.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

有小伙伴可能会说放在 Cookie 中不是又被黑客网站盗用了吗?其实不会的,大家注意如下两个问题:
(1)黑客网站根本不知道你的 Cookie 里边存的啥,他也不需要知道,因为 CSRF 攻击是浏览器自动携带上 Cookie 中的数据的。
(2)我们将服务端生成的随机数放在 Cookie 中,前端需要从 Cookie 中自己提取出来 _csrf 参数,然后拼接成参数传递给后端,单纯的将 Cookie 中的数据传到服务端是没用的。
理解透了上面两点,你就会发现 _csrf 放在 Cookie 中是没有问题的,但是大家注意,配置的时候我们通过 withHttpOnlyFalse 方法获取了 CookieCsrfTokenRepository 的实例,该方法会设置 Cookie 中的 HttpOnly 属性为 false,也就是允许前端通过 js 操作 Cookie(否则你就没有办法获取到 _csrf)。

配置完成后,重启项目,此时我们就发现返回的 Cookie 中多了一项:

CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

接下来,我们通过自定义登录页面,来看看前端要如何操作。

首先我们在 resources/static 目录下新建一个 html 页面叫做 login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
</head>
<body>
<div>
    <input type="text" id="username">
    <input type="password" id="password">
    <input type="button" value="登录" id="loginBtn">
</div>
<script>
    $("#loginBtn").click(function () {
        let _csrf = $.cookie(&#39;XSRF-TOKEN&#39;);
        $.post(&#39;/login.html&#39;,{username:$("#username").val(),password:$("#password").val(),_csrf:_csrf},function (data) {
            alert(data);
        })
    })
</script>
</body>
</html>

这段 html 给大家解释一下:
(1)首先引入 jquery 和 jquery.cookie ,方便我们一会操作 Cookie。
(2)定义三个 input,前两个是用户名和密码,第三个是登录按钮。
(3)点击登录按钮之后,我们先从 Cookie 中提取出 XSRF-TOKEN,这也就是我们要上传的 csrf 参数。
(4)通过一个 POST 请求执行登录操作,注意携带上 _csrf 参数。

服务端我们也稍作修改,如下:

package com.mry.csrf.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/js/**");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login.html")
                .successHandler((req,resp,authentication)->{
                    resp.getWriter().write("success");
                })
                .permitAll()
                .and()
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

一方面这里给 js 文件放行。

另一方面配置一下登录页面,以及登录成功的回调,这里简单期间,登录成功的回调我就给一个字符串就可以了。在登录成功后回调的详细解释。

OK,所有事情做完之后,我们访问 login.html 页面,输入用户名密码进行登录,结果如下:

CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?

可以看到,我们的 _csrf 配置已经生效了。

위 내용은 CSRF 공격에 대한 SpringBoot의 방어 프로세스와 원칙은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 亿速云에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
Java 개발의 어떤 측면이 플랫폼 의존적입니까?Java 개발의 어떤 측면이 플랫폼 의존적입니까?Apr 26, 2025 am 12:19 AM

javadevelopmentisnotentirelyplatform-IndectionentDuetoSeveralFactors.1) JVMVARIATIONSAFFERFFERFORMANDBEHAVIORACROSSDIFFERENTOS.2) nativelibrariesViajniintrictionPlatform-specificiss.3) filepathsandsystempropertiesdifferbetweenplatectry. 4)

다른 플랫폼에서 Java 코드를 실행할 때 성능 차이가 있습니까? 왜?다른 플랫폼에서 Java 코드를 실행할 때 성능 차이가 있습니까? 왜?Apr 26, 2025 am 12:15 AM

Java 코드는 다른 플랫폼에서 실행할 때 성능 차이가 있습니다. 1) JVM의 구현 및 최적화 전략은 OracleJDK 및 OpenJDK와 같이 다릅니다. 2) 메모리 관리 및 스레드 스케줄링과 같은 운영 체제의 특성도 성능에 영향을 미칩니다. 3) 적절한 JVM을 선택하여 JVM 매개 변수 및 코드 최적화를 조정하여 성능을 향상시킬 수 있습니다.

Java의 플랫폼 독립성의 몇 가지 한계는 무엇입니까?Java의 플랫폼 독립성의 몇 가지 한계는 무엇입니까?Apr 26, 2025 am 12:10 AM

Java'SplatformIndenceHASLIMITATIONSINTERFORMANTOWORHEAD, 버전 컴포팅 가능성, 도전 과제, 플랫폼-특이 적 식품, 및 JVMINSTALLATION/MAYMENDENT.ThesefacteThe "WriteOnce, Runanywhere"

플랫폼 독립성과 크로스 플랫폼 개발의 차이점을 설명하십시오.플랫폼 독립성과 크로스 플랫폼 개발의 차이점을 설명하십시오.Apr 26, 2025 am 12:08 AM

Platform IndependenCealLowsProgramStorunannyplatformwithoutModification, whileCross-PlatformDevelopmentRequiressomplatformspecificAdJustments.platformIndence, PreemplifiedByjava, enableStalExecutionButmayPromiseperformance.cross-platformd

JIT (Just-In-Time) 컴파일은 Java의 성능 및 플랫폼 독립에 어떤 영향을 미칩니 까?JIT (Just-In-Time) 컴파일은 Java의 성능 및 플랫폼 독립에 어떤 영향을 미칩니 까?Apr 26, 2025 am 12:02 AM

jitcompilationinjavaenhancesperformance는 platformindence.1) ItdynamicallyTransLatesByTecodeIntonativeMachinecodeatimeTime, 최적화 FREQUELTEREDCODE.2) TheJVMREMAINSPLATFORM- Independent, 허용 THEMEJAVAAPPLITIONTORUNONDIFFEREN을 허용합니다

Java가 크로스 플랫폼 데스크톱 응용 프로그램을 개발하기 위해 인기있는 선택 인 이유는 무엇입니까?Java가 크로스 플랫폼 데스크톱 응용 프로그램을 개발하기 위해 인기있는 선택 인 이유는 무엇입니까?Apr 25, 2025 am 12:23 AM

javaispopularforcross-platformdesktopapplicationsduetoits "writeonce, runanywhere"철학

Java의 플랫폼 별 코드 작성 상황에 대해 토론하십시오.Java의 플랫폼 별 코드 작성 상황에 대해 토론하십시오.Apr 25, 2025 am 12:22 AM

Java에서 플랫폼 별 코드를 작성하는 이유에는 특정 운영 체제 기능에 대한 액세스, 특정 하드웨어와 상호 작용하고 성능 최적화가 포함됩니다. 1) JNA 또는 JNI를 사용하여 Windows 레지스트리에 액세스하십시오. 2) JNI를 통한 Linux 특이 적 하드웨어 드라이버와 상호 작용; 3) 금속을 사용하여 JNI를 통해 MacOS의 게임 성능을 최적화하십시오. 그럼에도 불구하고 플랫폼 별 코드를 작성하면 코드의 이식성에 영향을 미치고 복잡성을 높이며 잠재적으로 성능 오버 헤드 및 보안 위험을 초래할 수 있습니다.

플랫폼 독립성과 관련된 Java 개발의 미래 트렌드는 무엇입니까?플랫폼 독립성과 관련된 Java 개발의 미래 트렌드는 무엇입니까?Apr 25, 2025 am 12:12 AM

Java는 Cloud-Native Applications, Multi-Platform 배포 및 교차 운용성을 통해 플랫폼 독립성을 더욱 향상시킬 것입니다. 1) Cloud Native Applications는 Graalvm 및 Quarkus를 사용하여 시작 속도를 높입니다. 2) Java는 임베디드 장치, 모바일 장치 및 양자 컴퓨터로 확장됩니다. 3) Graalvm을 통해 Java는 Python 및 JavaScript와 같은 언어와 완벽하게 통합되어 언어 교차 수용 가능성을 향상시킵니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구