IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 19.SpringSecurity-web权限方案-CSRF功能 -> 正文阅读

[网络协议]19.SpringSecurity-web权限方案-CSRF功能

CSRF 理解

??跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

??跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。

??这利用了 web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

??从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法进行防护。

案例

??SecurityConfig:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    UserDetailsService userDetailsService;

    //实现用户身份认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置url的访问权限
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/**update**").permitAll()
                .antMatchers("/login/**").permitAll()
                .anyRequest().authenticated();

        //关闭csrf保护功能
        //http.csrf().disable();
//       
        //使用自定义的登录窗口
      http.formLogin()
              .loginPage("/userLogin").permitAll()
              .usernameParameter("username").passwordParameter("password")
              .defaultSuccessUrl("/")
              .failureUrl("/userLogin?error");
    }
} 

??controller:

@Controller
public class CSRFController {

     @GetMapping("/toupdate")
     public String test(Model model){
         return "csrf/csrfTest";
     }

    @PostMapping("/update_token")
    public String getToken() {
        return "csrf/csrf_token";
    }
}
@Controller
public class LoginController {
    @GetMapping("/userLogin")
    public String login(){
        return "login/login";
    }
}

??UserDetailsServiceImpl:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

            List<SimpleGrantedAuthority> list = new ArrayList<>();
            list.add(new SimpleGrantedAuthority("role"));
            UserDetails userDetails = new User("lisi", new BCryptPasswordEncoder().encode("996")
                    , list);
            return userDetails;
    }
}

??pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zsc</groupId>
    <artifactId>ch07-security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ch07-security</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--对Thymeleaf添加Spring Security标签支持-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.14</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
    </dependencies>
</project>

??登录html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户修改</title>
</head>
<body>
<div align="center">
    <form  method="post" action="update_token">
      <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
        用户名: <input type="text" name="username" /><br />&nbsp;&nbsp;码: <input type="password" name="password" /><br />
        <button type="submit">修改</button>
    </form>
</div>
</body>
</html

??token展示html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户修改</title>
</head>
<body>
<div>
    <span th:text="${_csrf.token}"></span>
</div>

</body>
</html>

??测试:
请添加图片描述

??客户端访问的时候会进行认证,认证过程中生成 csrfToken 保存到 HttpSession 或者 Cookie 中,再次进行访问的时候带着token字符串和session中存储的token进行比较,一致的情况下才允许访问。

源码

??CsrfFilter:这是做csrf防护的过滤器,核心是doFilterInternal方法

@Override
protected void doFilterInternal(HttpServletRequest request,
      HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
   request.setAttribute(HttpServletResponse.class.getName(), response);
   //生成一个Token,并存到session中
   CsrfToken csrfToken = this.tokenRepository.loadToken(request);
   final boolean missingToken = csrfToken == null;
   if (missingToken) {
      csrfToken = this.tokenRepository.generateToken(request);
      this.tokenRepository.saveToken(csrfToken, request, response);
   }
   request.setAttribute(CsrfToken.class.getName(), csrfToken);
   //csrfToken.getParameterName(),获取表单中传进来的Token值
   request.setAttribute(csrfToken.getParameterName(), csrfToken);
   //进行比较,若不一致则返回,若一致则执行后续逻辑 
   if (!this.requireCsrfProtectionMatcher.matches(request)) {
      filterChain.doFilter(request, response);
      return;
   }

   String actualToken = request.getHeader(csrfToken.getHeaderName());
   if (actualToken == null) {
      actualToken = request.getParameter(csrfToken.getParameterName());
   }
   if (!csrfToken.getToken().equals(actualToken)) {
      if (this.logger.isDebugEnabled()) {
         this.logger.debug("Invalid CSRF token found for "
               + UrlUtils.buildFullRequestUrl(request));
      }
      if (missingToken) {
         this.accessDeniedHandler.handle(request, response,
               new MissingCsrfTokenException(actualToken));
      }
      else {
         this.accessDeniedHandler.handle(request, response,
               new InvalidCsrfTokenException(csrfToken, actualToken));
      }
      return;
   }

   filterChain.doFilter(request, response);
}

??注意看这段代码:

if (!this.requireCsrfProtectionMatcher.matches(request)) {
   filterChain.doFilter(request, response);
   return;
}

??比对的时候使用的是requireCsrfProtectionMatcher

public final class CsrfFilter extends OncePerRequestFilter {
   /**
    * The default {@link RequestMatcher} that indicates if CSRF protection is required or
    * not. The default is to ignore GET, HEAD, TRACE, OPTIONS and process all other
    * requests.
    */
   public static final RequestMatcher DEFAULT_CSRF_MATCHER = new DefaultRequiresCsrfMatcher();

   /**
    * The attribute name to use when marking a given request as one that should not be filtered.
    *
    * To use, set the attribute on your {@link HttpServletRequest}:
    * <pre>
    *     CsrfFilter.skipRequest(request);
    * </pre>
    */
   private static final String SHOULD_NOT_FILTER = "SHOULD_NOT_FILTER" + CsrfFilter.class.getName();

   private final Log logger = LogFactory.getLog(getClass());
   private final CsrfTokenRepository tokenRepository;
   private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
   private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
   }

??我们往翻发现它的实现实际上是DefaultRequiresCsrfMatcher,而防护的时候下面的这些请求是不做防护的;

private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
   private final HashSet<String> allowedMethods = new HashSet<>(
         Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 13:06:47  更:2022-05-09 13:07:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:36:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码