共计 9489 个字符,预计需要花费 24 分钟才能阅读完成。
1. XSS 跨站脚本攻打
①:XSS 破绽介绍
跨站脚本攻打 XSS 是指攻击者往 Web 页面里插入歹意 Script 代码,当用户浏览该页之时,嵌入其中 Web 外面的 Script 代码会被解析执行,从而达到歹意攻打用户的目标。XSS 攻打针对的是用户层面的攻打!
②:XSS 破绽分类
存储型 XSS: 存储型 XSS,长久化,代码是存储在服务器中的,如在个人信息或发表文章等中央,插入代码,如果没有过滤或过滤不严,那么这些代码将贮存到服务器中,用户拜访该页面的时候触发代码执行。这种 XSS 比拟危险,容易造成蠕虫,偷盗 cookie
反射型 XSS: 非长久化,须要坑骗用户本人去点击链接能力触发 XSS 代码(服务器中没有这样的页面和内容),个别容易呈现在搜寻页面
DOM 型 XSS: 不通过后端,DOM-XSS 破绽是基于文档对象模型 (Document Objeet Model
,DOM) 的一种破绽,DOM-XSS 是通过 url 传入参数去管制触发的,其实也属于反射型 XSS。
③:防护倡议
- 限度用户输出,表单数据规定值得类型,例如年龄只能是 int,name 为字母数字组合。
- 对数据进行 html encode 解决。
- 过滤或移除非凡的 html 标签。
- 过滤 javascript 事件的标签。
2. SQL 注入攻打
①:SQL 注入破绽介绍
SQL 注入(SQLi)是一种注入攻打,能够执行歹意 SQL 语句。它通过将任意 SQL 代码插入数据库查问,使攻击者可能齐全管制 Web 应用程序前面的数据库服务器。攻击者能够应用 SQL 注入破绽绕过应用程序安全措施;能够绕过网页或 Web 应用程序的身份验证和受权,并检索整个 SQL 数据库的内容;还能够应用 SQL 注入来增加,批改和删除数据库中的记录
SQL 注入破绽可能会影响应用 SQL 数据库(如 MySQL,Oracle,SQL Server 或其余)的任何网站或 Web 应用程序。犯罪分子可能会利用它来未经受权拜访用户的敏感数据:客户信息,集体数据,商业秘密,知识产权等。SQL 注入攻打是最古老,最风行,最危险的 Web 应用程序破绽之一。
②:防护倡议
应用 mybatis 中 #{}
能够无效避免 sql 注入
- 应用
#{}
时:
<select id="getBlogById" resultType="Blog" parameterType=”int”> | |
select id,title,author,content | |
from blog where id=#{id} | |
</select> |
打印出执行的 sql 语句,会看到 sql 是这样的:
select id,title,author,content from blog where id = ?
不论输出什么参数,打印出的 sql 都是这样的。这是因为 mybatis 启用了预编译性能,在 sql 执行前,会先将下面的 sql 发送给数据库进行编译,执行时,间接应用编译好的 sql,替换占位符“?”就能够了。因为 sql 注入只能对编译过程起作用,所以像 #{}这样预编译成?的形式就很好地防止了 sql 注入的问题。
mybatis 是如何做到 sql 预编译的呢?
其实在框架底层,是 jdbc 中的 PreparedStatement
类在起作用,PreparedStatement
是咱们很相熟的 Statement 的子类,它的对象蕴含了编译好的 sql 语句。这种“筹备好”的形式不仅能进步安全性,而且在屡次执行一个 sql 时,可能提高效率,起因是 sql 已编译好,再次执行时无需再编译。
- 应用
${}
时
<select id="orderBlog" resultType="Blog" parameterType=”map”> | |
select id,title,author,content | |
from blog order by ${orderParam} | |
</select> |
仔细观察,内联参数的格局由“#{xxx}
”变为了${xxx}
。如果咱们给参数“orderParam
”赋值为”id”, 将 sql 打印进去,是这样的:
select id,title,author,contet from blog order by id
显然,这样是无奈阻止 sql 注入的,参数会直接参与 sql 编译,从而不能防止注入攻打。但波及到动静表名和列名时,只能应用“${}
”这样的参数格局,所以,这样的参数须要咱们在代码中手工进行解决来避免注入。
3. SpringBoot 中如何避免 XSS 攻打和 sql 注入
话不多说,上代码
Spring Boot 根底就不介绍了,举荐看这个收费教程:
https://github.com/javastacks/spring-boot-best-practice
对于 Xss 攻打和 Sql 注入,咱们能够通过过滤器来搞定,可依据业务须要排除局部申请
①:创立 Xss 申请过滤类XssHttpServletRequestWraper
代码如下:
public class XssHttpServletRequestWraper extends HttpServletRequestWrapper {Logger log = LoggerFactory.getLogger(this.getClass()); | |
public XssHttpServletRequestWraper() {super(null); | |
} | |
public XssHttpServletRequestWraper(HttpServletRequest httpservletrequest) {super(httpservletrequest); | |
} | |
// 过滤 springmvc 中的 @RequestParam 注解中的参数 | |
public String[] getParameterValues(String s) {String str[] = super.getParameterValues(s); | |
if (str == null) {return null;} | |
int i = str.length; | |
String as1[] = new String[i]; | |
for (int j = 0; j < i; j++) {//System.out.println("getParameterValues:"+str[j]); | |
as1[j] = cleanXSS(cleanSQLInject(str[j])); | |
} | |
log.info("XssHttpServletRequestWraper 污染后的申请为:==========" + as1); | |
return as1; | |
} | |
// 过滤 request.getParameter 的参数 | |
public String getParameter(String s) {String s1 = super.getParameter(s); | |
if (s1 == null) {return null;} else {String s2 = cleanXSS(cleanSQLInject(s1)); | |
log.info("XssHttpServletRequestWraper 污染后的申请为:==========" + s2); | |
return s2; | |
} | |
} | |
// 过滤申请体 json 格局的 | |
@Override | |
public ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); | |
return new ServletInputStream() { | |
@Override | |
public int read() throws IOException {return bais.read(); | |
} | |
@Override | |
public boolean isFinished() {return false;} | |
@Override | |
public boolean isReady() {return false;} | |
@Override | |
public void setReadListener(ReadListener readListener) {}}; | |
} | |
public String inputHandlers(ServletInputStream servletInputStream){StringBuilder sb = new StringBuilder(); | |
BufferedReader reader = null; | |
try {reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8"))); | |
String line = ""; | |
while ((line = reader.readLine()) != null) {sb.append(line); | |
} | |
} catch (IOException e) {e.printStackTrace(); | |
} finally {if (servletInputStream != null) { | |
try {servletInputStream.close(); | |
} catch (IOException e) {e.printStackTrace(); | |
} | |
} | |
if (reader != null) { | |
try {reader.close(); | |
} catch (IOException e) {e.printStackTrace(); | |
} | |
} | |
} | |
return cleanXSS(sb.toString ()); | |
} | |
public String cleanXSS(String src) { | |
String temp = src; | |
src = src.replaceAll("<", "<").replaceAll(">", ">"); | |
src = src.replaceAll("\\(", "(").replaceAll("\\)", ")"); | |
src = src.replaceAll("'","'"); | |
src = src.replaceAll(";", ";"); | |
//bgh 2018/05/30 新增 | |
/**-----------------------start--------------------------*/ | |
src = src.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); | |
src = src.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41"); | |
src = src.replaceAll("eval\\((.*)\\)", ""); | |
src = src.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); | |
src = src.replaceAll("script", ""); | |
src = src.replaceAll("link", ""); | |
src = src.replaceAll("frame", ""); | |
/**-----------------------end--------------------------*/ | |
Pattern pattern = Pattern.compile("(eval\\((.*)\\)|script)", | |
Pattern.CASE_INSENSITIVE); | |
Matcher matcher = pattern.matcher(src); | |
src = matcher.replaceAll(""); | |
pattern = Pattern.compile("[\\\"\\'][\\s]*javascript:(.*)[\\\"\\']", | |
Pattern.CASE_INSENSITIVE); | |
matcher = pattern.matcher(src); | |
src = matcher.replaceAll("\"\""); | |
// 减少脚本 | |
src = src.replaceAll("script", "").replaceAll(";","") | |
/*.replaceAll("\"", "").replaceAll("@","")*/ | |
.replaceAll("0x0d", "").replaceAll("0x0a",""); | |
if (!temp.equals(src)) {// System.out.println("输出信息存在 xss 攻打!"); | |
// System.out.println("原始输出信息 -->" + temp); | |
// System.out.println("解决后信息 -->" + src); | |
log.error("xss 攻打查看:参数含有非法攻打字符,已禁止持续拜访!!"); | |
log.error("原始输出信息 -->" + temp); | |
throw new CustomerException("xss 攻打查看:参数含有非法攻打字符,已禁止持续拜访!!"); | |
} | |
return src; | |
} | |
// 输入 | |
public void outputMsgByOutputStream(HttpServletResponse response, String msg) throws IOException {ServletOutputStream outputStream = response.getOutputStream(); // 获取输入流 | |
response.setHeader("content-type", "text/html;charset=UTF-8"); // 通过设置响应头管制浏览器以 UTF- 8 的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码 | |
byte[] dataByteArr = msg.getBytes("UTF-8");// 将字符转换成字节数组,指定以 UTF- 8 编码进行转换 | |
outputStream.write(dataByteArr);// 应用 OutputStream 流向客户端输入字节数组 | |
} | |
// 须要减少通配,过滤大小写组合 | |
public String cleanSQLInject(String src) {String lowSrc = src.toLowerCase(); | |
String temp = src; | |
String lowSrcAfter = lowSrc.replaceAll("insert", "forbidI") | |
.replaceAll("select", "forbidS") | |
.replaceAll("update", "forbidU") | |
.replaceAll("delete", "forbidD").replaceAll("and", "forbidA") | |
.replaceAll("or", "forbidO"); | |
if (!lowSrcAfter.equals(lowSrc)) {log.error("sql 注入查看:输出信息存在 SQL 攻打!"); | |
log.error("原始输出信息 -->" + temp); | |
log.error("解决后信息 -->" + lowSrc); | |
throw new CustomerException("sql 注入查看:参数含有非法攻打字符,已禁止持续拜访!!"); | |
} | |
return src; | |
} | |
} |
②:把申请过滤类 XssHttpServletRequestWraper
增加到 Filter 中,注入容器
@Component | |
public class XssFilter implements Filter {Logger log = LoggerFactory.getLogger(this.getClass()); | |
// 疏忽权限查看的 url 地址 | |
private final String[] excludeUrls = new String[]{"null"}; | |
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) | |
throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) arg0; | |
HttpServletResponse response = (HttpServletResponse) arg1; | |
String pathInfo = req.getPathInfo() == null ? "" : req.getPathInfo(); | |
// 获取申请 url 的后两层 | |
String url = req.getServletPath() + pathInfo; | |
// 获取申请你 ip 后的全副门路 | |
String uri = req.getRequestURI(); | |
// 注入 xss 过滤器实例 | |
XssHttpServletRequestWraper reqW = new XssHttpServletRequestWraper(req); | |
// 过滤掉不须要的 Xss 校验的地址 | |
for (String str : excludeUrls) {if (uri.indexOf(str) >= 0) {arg2.doFilter(arg0, response); | |
return; | |
} | |
} | |
// 过滤 | |
arg2.doFilter(reqW, response); | |
} | |
public void destroy() {} | |
public void init(FilterConfig filterconfig1) throws ServletException {}} |
上述代码曾经能够实现 申请参数、JSON 申请体 的过滤,但对于 json 申请体还有其余的形式实现,有趣味的请看上面的扩大!
扩大:还能够重写 spring 中的 MappingJackson2HttpMessageConverter
来过滤 Json 申请体
因为申请体在进出 Contoroller 时,会通过 MappingJackson2HttpMessageConverter
的一个转换,把申请体转换成咱们须要的 json 格局,所以能够在这里边做一些批改!
@Configuration | |
public class MyConfiguration { | |
@Bean | |
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){ | |
// 自定义转换器 | |
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); | |
// 转换器日期格局设置 | |
ObjectMapper objectMapper = new ObjectMapper(); | |
SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
objectMapper.setDateFormat(smt); | |
converter.setObjectMapper(objectMapper); | |
// 转换器增加自定义 Module 扩大,次要是在这里做 XSS 过滤的!!,其余的是其余业务,不必看 | |
SimpleModule simpleModule = new SimpleModule(); | |
// 增加过滤逻辑类!simpleModule.addDeserializer(String.class,new StringDeserializer()); | |
converter.getObjectMapper().registerModule(simpleModule); | |
// 设置中文编码格局 | |
List<MediaType> list = new ArrayList<>(); | |
list.add(MediaType.APPLICATION_JSON_UTF8); | |
converter.setSupportedMediaTypes(list); | |
return converter; | |
} | |
} |
真正的过滤逻辑类StringDeserializer
:
// 测验申请体的参数 | |
@Component | |
public class StringDeserializer extends JsonDeserializer<String> { | |
@Override | |
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {String str = jsonParser.getText().trim(); | |
//sql 注入拦挡 | |
if (sqlInject(str)) {throw new CustomerException("参数含有非法攻打字符,已禁止持续拜访!"); | |
} | |
return xssClean(str); | |
} | |
public boolean sqlInject(String str) {if (StringUtils.isEmpty(str)) {return false;} | |
// 去掉 '|"|;|\ 字符 | |
str = org.apache.commons.lang3.StringUtils.replace(str, "'",""); | |
str = org.apache.commons.lang3.StringUtils.replace(str, "\"", ""); | |
str = org.apache.commons.lang3.StringUtils.replace(str, ";", ""); | |
str = org.apache.commons.lang3.StringUtils.replace(str, "\\", ""); | |
// 转换成小写 | |
str = str.toLowerCase(); | |
// 非法字符 | |
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert","alter", "drop"}; | |
// 判断是否蕴含非法字符 | |
for (String keyword : keywords) {if (str.indexOf(keyword) != -1) {return true;} | |
} | |
return false; | |
} | |
//xss 攻打拦挡 | |
public String xssClean(String value) {if (value == null || "".equals(value)) {return value;} | |
// 非法字符 | |
String[] keywords = {"<", ">", "<>", "()", ")", "(", "javascript:", "script","alter", "''","'"}; | |
// 判断是否蕴含非法字符 | |
for (String keyword : keywords) {if (value.indexOf(keyword) != -1) {throw new CustomerException("参数含有非法攻打字符,已禁止持续拜访!"); | |
} | |
} | |
return value; | |
} | |
} |
应用这种模式也能够实现 json 申请体的过滤,但集体更举荐应用 XssHttpServletRequestWraper
的模式来实现 xss 过滤!!
起源:blog.csdn.net/qq_45076180/article/details/115000495
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!