目录
3-2、XssHttpServletRequestWrapper类过滤http请求
一、Spring Boot项目打包成war包
1、Eclipse开发工具
1-1、在pom.xml中,将打包方式改成war
<packaging>war</packaging>
1-2、在pom.xml中,设置打成的war名字
<!-- 属性配置 -->
<properties>
<fileName>springboot01</fileName>
</properties>
<!-- 设置war包名称 -->
<build>
<finalName>${fileName}</finalName>
</build>
1-3、添加启动类ServletInitializer
说明:在启动类Springboot01Application中继承SpringBootServletInitializer类
@SpringBootApplication
public class Springboot01Application extends SpringBootServletInitializer {
/**
* 不挂断启动:可使用【nohup -jar springboot01.war &】
*
* @param args 参数
*/
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Springboot01Application.class);
app.setBannerMode(Banner.Mode.CONSOLE); // OFF - 不打印图案
app.run(args);
}
/**
* 使用tomcat启动
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Springboot01Application.class);
}
}
1-4、打war包
① 选中要打war的项目(鼠标左键点击一下项目)
② 鼠标右键点击一下,会弹出菜单选项;光标定位在Run As或Debug As上
③ 出现次菜单,选择Maven install即可。(也可以先Maven clean下)
1-5、启动方式
(1)使用命令启动war
① 启动:后端运行,即不挂断运行命令:nohup java -jar 项目名.jar/war &
示例:nohup java -jar springboot01.war &
② 停止:脚本内容如下,使用命令 sh stop.sh 可停止项目
# grep -v grep 过滤掉含有grep的行,$2第二个参数(即第二列) PID=`ps -ef | grep simulator-web.war | grep -v grep | awk '{print $2}'` # -z "${pid}"判断pid是否存在 if [ -z "$PID" ] then echo "应用程序已经停止了" else echo kill $PID kill -9 $PID echo "程序已被kill -9了" fi
grep -v 意为不包括:上述语句的意思是查找除了grep下的所有信息
awk '{print $2}':取第二个字段输出。($0表示整个当前行,$1每行第一个字段)
awk [-F|-f|-v]:[-F|-f|-v] 大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
示例:awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd // 输出字段1,3,6,以制表符作为分隔符
awk -F: '{print $1; print $2}' /etc/passwd // 将每一行的前二个字段,分行输出,进一步理解一行一行处理文本(print 会换行)
awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd // 输出字段1,3,6,以制表符作为分隔符
(2) 使用tomcat启动war
在bin目录下,catalina.sh中添加使用的JDK版本:export JAVA_HOME="/opt/jdk1.7.0_80"
在bin目录下,catalina.sh中添加JVM参数:export JAVA_OPTS="......"
最后把war放入tomcat的webapps下,然后进入bin目录,执行命令:sh startup.sh
2、IntelliJ IDEA 开发工具
2-1、初始配置
说明:初始配置步骤同【1-1、1-2、1-3】一样;启动项目同【1-5】一样
2-2、打war包
图1:选择“Build” -》Build Artifacts...,点击,会出现图2
图2:鼠标的光标移动到横三角形上,会出现要执行的操作:Build、Rebuild、Clean、Edit;打包选择Build即可
二、防御XSS攻击
跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
使用Jsoup可以有效的过滤不安全的代码。Jsoup使用白名单的机制来预防XSS攻击,比如白名单中规定只允许<span>标签的存在,那么其他标签都会被过滤掉
1、常见的XSS攻击
备注加入<style>body{color:red !important}</style>保存后,会发现页面的文字变红,而且排版出现问题。或者加入<script>alert("这个是bug");</script>保存后会弹出【这个是bug】
2、pom.xml引入Jsoup包
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.9.2</version>
</dependency>
3、Xss过滤工具
3-1、JsoupUtil工具类
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;
/**
* Xss过滤工具
*/
public class JsoupUtil {
// 使用自带的 basicWithImages 白名单
private static final Whitelist WHITELIST = Whitelist.basicWithImages();
// 配置过滤化参数, 不对代码进行格式化
private static final Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
static {
// WHITELIST.addTags("div", "h1"); 添加白名单属性,如div, h1为白名单不会被过滤
// :all 表明给白名单中的所有标签添加 style 属性;如果如div, h1白名单标签有style属性就不会被过滤
WHITELIST.addAttributes(":all", "style");
}
public static String clean(String content) {
// 使用Whitelist对输入的Html文档过滤,只允许特定的标签或者属性,防止恶意代码
return Jsoup.clean(content, "", WHITELIST, outputSettings);
}
}
3-2、XssHttpServletRequestWrapper类过滤http请求
创建一个XssHttpServletRequestWrapper,通过重写
getParameter()
,getParameterValues()
和getHeader()
方法来过滤HTTP请求中参数包含的恶意字符
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private boolean isIncludeRichText;
XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText) {
super(request);
this.isIncludeRichText = isIncludeRichText;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤,
* 如果需要获得原始的值,则通过super.getParameter(name) 和 super.getParameterValues(name)来获取
*
* @param name 参数名
* @return String
*/
@Override
public String getParameter(String name) {
if (!isIncludeRichText) {
return super.getParameter(name);
}
name = JsoupUtil.clean(name);
String value = super.getParameter(name);
if (StringUtil.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] arr = super.getParameterValues(name);
if (arr != null) {
for (int i = 0; i < arr.length; i++) {
arr[i] = JsoupUtil.clean(arr[i]);
}
}
return arr;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤,如果需要获得原始的值,则通过super.getHeaders(name)来获取
*/
@Override
public String getHeader(String name) {
name = JsoupUtil.clean(name);
String value = super.getHeader(name);
if (StringUtil.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
}
3-3、XssFilter
public class XssFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(XssFilter.class);
// 是否过滤富文本内容
private static boolean IS_INCLUDE_RICH_TEXT = false;
private List<String> excludes = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) {
log.info("------------ xss filter init ------------");
String isIncludeRichText = filterConfig.getInitParameter("isIncludeRichText");
if (StringUtil.isNotBlank(isIncludeRichText)) {
IS_INCLUDE_RICH_TEXT = Boolean.valueOf(isIncludeRichText);
}
String temp = filterConfig.getInitParameter("excludes");
if (temp != null) {
String[] url = temp.split(",");
for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp)) {
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request, IS_INCLUDE_RICH_TEXT);
chain.doFilter(xssRequest, response);
}
@Override
public void destroy() {
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
if (excludes == null || excludes.isEmpty()) {
return false;
}
String url = request.getServletPath();
for (String pattern : excludes) {
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find()) {
return true;
}
}
return false;
}
}
3-4、XssFilterConfig配置
@Configuration
public class XssFilterConfig {
@Bean
public FilterRegistrationBean xssFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new XssFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/*");
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("excludes", "/favicon.ico,/img/*,/js/*,/css/*");
initParameters.put("isIncludeRichText", "true");
filterRegistrationBean.setInitParameters(initParameters);
return filterRegistrationBean;
}
}
3-5、参考文章
https://mrbird.cc/Jsoup%20XSS.html
https://www.jianshu.com/p/32abc12a175a?nomobile=yes
三、Spring Boot异常处理
Spring Boot对异常的处理有一套默认的机制:当应用中产生异常时,Spring Boot根据发送请求头中的accept是否包含text/html来分别返回不同的响应信息。
① 从浏览器地址栏中访问应用接口时,请求头中的accept便会包含text/html信息,产生异常时,Spring Boot通过org.springframework.web.servlet.ModelAndView对象来装载异常信息,并以HTML的格式返回
② 当从客户端访问应用接口产生异常时(客户端访问时,请求头中的accept不包含text/html),Spring Boot则以JSON的格式返回异常信息
1、控制层抛出异常
@Controller
public class ExceptionController {
private static final Logger log = LoggerFactory.getLogger(ExceptionController.class);
/**
* @param id 参数
*/
@GetMapping("/{id:\\d+}")
public void testException(@PathVariable String id) {
log.debug("test exception:throw new TestException,id={}", id);
throw new TestException("E00001", "测试抛出异常");
}
}
2、自定义异常类
public class TestException extends RuntimeException {
private static final long serialVersionUID = 1562583731949234181L;
private String code;
private String message;
public TestException(String code, String message) {
super(message);
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String msg) {
this.message = msg;
}
}
3、处理异常类
import org.springboot.springboot01.exception.TestException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.HashMap;
import java.util.Map;
/**
* 异常处理类,可处理自定义异常
*/
@ControllerAdvice
public class ControllerExceptionHandler {
/**
* 使用了@ResponseBody,返回的内容会是JSON格式
*/
@ExceptionHandler(TestException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, Object> handleUserNotExistsException(TestException e) {
Map<String, Object> map = new HashMap<>();
map.put("code", e.getCode());
map.put("message", e.getMessage());
return map;
}
}