第6章 会话管理
6.2 配置防御会话固定攻击
protected void configure(HttpSecurity http) throws Exception {
//自动登录的令牌持久化到
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/API/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
//自定义登录页
/*.loginPage("/myLogin.html")
.loginProcessingUrl("/login")
.permitAll() */
.and()
.rememberMe()
.and()
// 配置 配置防御回话固定攻击策略
.sessionManagement().sessionFixation().newSession()
.and()
.csrf().disable();
}
6.3 会话过期
1、配置session过期跳转某个路由
// 配置 配置防御回话固定攻击策略
.sessionManagement().sessionFixation().newSession()
// 配置session过期跳转的路由
.invalidSessionUrl("/session/invalid")
2、自定义session过期策略
public class MyInvalidSessionStrategy implements InvalidSessionStrategy{
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
ResponseData<String> res = new ResponseData<>(500, "sesson过期");
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().write(JSON.toJSONString(res));
}
}
.and()
// 配置 配置防御回话固定攻击策略
.sessionManagement().sessionFixation().newSession()
// 配置session过期跳转的路由
// .invalidSessionUrl("/session/invalid")
// 配置session过期的处理策略
.invalidSessionStrategy(new MyInvalidSessionStrategy())
6.4 session 并发控制
设置session的并发数为1
当在一个session会话中登陆后,在另一个session会话中进行登录时,第一个sessiong会话会过期
.sessionManagement().sessionFixation().newSession()
// 配置session过期跳转的路由
// .invalidSessionUrl("/session/invalid")
// 配置session过期的处理策略
.invalidSessionStrategy(new MyInvalidSessionStrategy())
// 配置session的并发数为1
.maximumSessions(1)
当在一个session会话中登陆后,在另一个session会话中进行登录时,登陆操作会被阻止
// 配置 配置防御回话固定攻击策略
.sessionManagement().sessionFixation().newSession()
// 配置session过期跳转的路由
// .invalidSessionUrl("/session/invalid")
// 配置session过期的处理策略
.invalidSessionStrategy(new MyInvalidSessionStrategy())
// 配置session的并发数为1
.maximumSessions(1)
.maxSessionsPreventsLogin(true);
第7章 密码加密
1、使用 BCryptPasswordEncoder 对用户密码进行加密
1)将BCryptPasswordEncoder 注入到容器中
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
2)WebSecurityConfig 中配置密码加密方式
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService)
.passwordEncoder(passwordEncoder);
}
2、如果将老系统的解密方式改造成BCrypt加密,并兼容历史数据
1)校验密码时,对数据库中存储的密码进行区分,如果不是BCrypt形式的,则使用以前老的校验密码的方式
2)不仅想要兼容,还想将不安全的旧密码无缝修改成BCrypt密文,该如何操作
有两种方式解决以上情况
- 使用增量更新的方式。当用户的密码输入正确时,判断数据库中的密码是否是Bcypt,如果不是,则尝试使用用户输入的密码 重新生成
Bcypt密文,并且回写数据库 - 以旧的加密方案作为基础接入Bcypt加密。例如,旧的方案是MD5加密,即数据库中的所有 密码都是 MD5形式的密码,那么直接把这些密码当作明文,先“跑库”生成 BCrypt 密文。再使用 encode 和 matches 两个方法在执行 BCrypt 加密之前都先用MD5运算一遍即可
第8章 跨域和cros
1、跨域的误解
很多人误认为资源跨域时无法请求,实际上,通常情况下请求是可以正常发起的(注意,部分浏 览器存在特例),后端也正常进行了处理,只是在返回时被浏览器拦截,导致响应内容不可使用
浏览器解决跨域问题的方法有多种,包括JSONP、Nginx转发和CORS等。其中,JSONP和CORS需 要后端参与。
2、cros实现跨域
CORS(Cross-Origin Resource Sharing)的规范中有一组新增的HTTP首部字段,允许服务器声明其 提供的资源允许哪些站点跨域使用。通常情况下,跨域请求即便在不被支持的情况下,服务器也会接 收并进行处理,在CORS的规范中则避免了这个问题。浏览器首先会发起一个请求方法为OPTIONS 的预检请求,用于确认服务器是否允许跨域,只有在得到许可后才会发出实际请求
CORS新增的HTTP首部字段由服务器控制,下面我们来看看常用的几个首部字段:
- Access-Control-Allow-Origin :
允许取值为或*。指被允许的站点,使用URL首部匹配原则。匹配所有站点,表 示允许来自所有域的请求。但并非所有情况都简单设置即可,如果需要浏览器在发起请求时携带凭证 信息,则不允许设置为。如果设置了具体的站点信息,则响应头中的 Vary字段还需要携带Origin属
性,因为服务器对不同的域会返回不同的内容 - Access-Control-Allow-Methods :
仅在预检请求的响应中指定有效,用于表明服务器允许跨域的 HTTP方法,多个方法之间用逗号隔开 - Access-Control-Allow-Headers
仅在预检请求的响应中指定有效,用于表明服务器允许携带的 首部字段。多个首部字段之间用逗号隔开 - Access-Control-Max-Age
字段用于指明本次预检请求的有效期,单位为秒。在有效期内,预检请 求不需要再次发起 - Access-Control-Allow-Credentials
当Access-Control-Allow-Credentials字段取值为true时,浏览器会在接下来的真实请求中携带用户凭证信息(cookie等),服务器也可以使用Set-Cookie向用户浏览器写入新的cookie。注意,使用AccessControl-Allow-Credentials时,Access-Control-Allow-Origin不应该设置为*。
简单请求、预检请求、带凭证的请求
-
简单请求
在CORS中,并非所有的跨域访问都会触发预检请求。例如,不携带自定义请求头信息的GET 请 求、HEAD 请求,以及 Content-Type 为application/x-www-form-urlencoded、multipart/form-data或text/plain的POST请求,这类请求被称为简单请求。 -
预检请求
text/plain的POST请求,这类请求被称为简单请求。
预检请求不同于简单请求,它会发送一个 OPTIONS 请求到目标站点,以查明该请求是否安全, 防止请求对目标站点的数据造成破坏。若是请求以 GET、HEAD、POST 以外的方法发起;或者使用 POST方法,但请求数据为application/x-www-form-urlencoded、multipart/form-data和text/plain以外的数据类型;再或者,使用了自定义请求头,则都会被当成预检请求类型处理 -
带凭证的请求
简单来说就是请求携带了cookie等信息
3、SpringSecurity对cros的支持
1)如何启用 SpringSecurity对cros的支持
只需在配置器中启用CORS支持,并编写一 个CORS配置源即可
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1、配置跨域
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
2)原理
DefaultCorsProcessor中的handleInternal方法
第九章 跨域请求伪造的防护
CSRF的全称是(Cross Site Request Forgery)
9.1 CSRF的攻击过程
9.2 CSRF的防御手段
1、HTTP Referer
HTTP Referer是由浏览器添加的一个请求头字段,用于标识请求来源。
2、CsrfToken认证
CSRF是利用用户的登录态进行攻击的,而用户的登录态记录在cookie中。其实攻击者并不知道用 户的cookie存放了哪些数据,于是想方设法让用户自身发起请求,这样浏览器便会自行将cookie传送到服务器完成身份校验