XSS, 跨站脚本攻击, 简单来说, 就是非本站点的脚本被执行了。 关于XSS 的详细介绍和防御参考:
![](https://img.kancloud.cn/43/58/4358b07e7d7def4a15bd89d4cb156ffe_600x460.png)
[XSS(跨站脚本)攻击与预防](https://blog.csdn.net/oscar999/article/details/127397397) 和 [跨站脚本攻击(XSS)及防范措施](https://blog.csdn.net/oscar999/article/details/105369085)。
本篇介绍在Java 项目中如何快速修复XSS 漏洞。本篇使用的是黑名单的方式, 对于非法字符进行转义。 黑名单的方式虽然不能完全的解决XSS的漏洞, 但是能有效的减轻攻击, 对于使用类似Coverity等代码静态扫描攻击扫描的漏洞, 修复之后就不会再报相关的警报了。
## 个别代码处理
如果整个项目中仅有几处被扫描出来存在XSS 攻击漏洞, 以基于Spring 项目的请求方法为例,下面的代码是存在XSS 漏洞的。
```
@RequestMapping("/unsafe")
public String unsafe(@RequestParam(required = false) String input) {
String s = "Hello";
s += input;
return s;
}
```
上面的代码中, 如果 input 包含了 `<script>`的脚本语句的话, 则这个响应返回给请求方的浏览器端, 相关的脚本就有可能被执行。
解决方法就是对返回的字符串进行黑名单过滤, 该怎么处理字符串呢? 内置tomcat 的jar 档- tomcat-embed-core-9.0.14.jar 提供了一个类: org.apache.tomcat.util.security.Escape , 该类中的htmlElementContent() 方法实现了对特殊字符转义,仿造这个方法写一个类似的htmlElementContent() , 完整代码如下:
```
public class SecurityUtil {
/**
* XSS 防御, 黑名单, 将非法字符进行替换
* @param content
* @return
*/
public static String htmlElementContent(String content) {
if (content == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if (c == '<') {
sb.append("<");
} else if (c == '>') {
sb.append(">");
} else if (c == '\'') {
sb.append("'");
} else if (c == '&') {
sb.append("&");
} else if (c == '"') {
sb.append(""");
} else if (c == '/') {
sb.append("/");
} else {
sb.append(c);
}
}
return (sb.length() > content.length()) ? sb.toString() : content;
}
}
```
对接口方法进行改写,响应的字符串通过htmlElementContent() 进行处理后则基本是安全的, 如下代码:
```
@RequestMapping("/safe")
public String safe(@RequestParam(required = false) String input) {
String s = "Hello";
s += input;
return SecurityUtil.htmlElementContent(s);
}
```
## 过滤器统一处理
如果是Java Web项目中, 如果每一个请求处理方法都使用上面方式进行处理的话, 则需要处理的地方太多了, 比较好的方式是使用过滤器进行统一处理。
过滤器可以对请求和响应进行XSS 防御的处理, 比如定义一个XssFilter 如下:
```
/**
* @Title: XssFilter.java
* @Package com.osxm.websecurity.xss
* @Description: TODO
* @author XM
* @date 2023年1月8日 下午8:09:35
* @Copyright: 2023
* @version V1.0
*/
package com.osxm.websecurity.xss;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* @ClassName XssFilter
* @Description TODO
* @author XM
* @date 2023年1月8日
*
*/
public class XssFilter {
FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssWrapper((HttpServletRequest) request), response);
}
}
```
在过滤器处理方法中, 使用XssWrapper对请求进行Xss 过滤, XssWrapper的内容如下:
```
/**
* @Title: XssWrapper.java
* @Package com.osxm.websecurity.xss
* @Description: TODO
* @author XM
* @date 2023年1月8日 下午8:10:49
* @Copyright: 2023
* @version V1.0
*/
package com.osxm.websecurity.xss;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @ClassName XssWrapper
* @Description TODO
* @author XM
* @date 2023年1月8日
*
*/
public class XssWrapper extends HttpServletRequestWrapper {
public static final String JSON_TYPE = "application/json";
public static final String CONTENT_TYPE = "Content-Type";
public static final String CHARSET = "UTF-8";
private String mBody;
HttpServletRequest originalRequest = null;
public XssWrapper(HttpServletRequest request) throws IOException {
super(request);
originalRequest = request;
setRequestBody(request.getInputStream());
}
/**
* 获取最原始的request。已经被getInputStream()了。
*
* @return
*/
public HttpServletRequest getOrgRequest() {
return originalRequest;
}
/**
* 获取最原始的request的静态方法。已经被getInputStream()了。
*
* @return
*/
public static HttpServletRequest getOriginalRequest(HttpServletRequest req) {
if (req instanceof XssWrapper) {
return ((XssWrapper) req).getOrgRequest();
}
return req;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (StringUtils.isBlank(value)) {
return value;
}
return StringEscapeUtils.escapeHtml4(value);
}
@Override
public String getQueryString() {
return StringUtils.isBlank(super.getQueryString()) ? "" : StringEscapeUtils.escapeHtml4(super.getQueryString());
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (StringUtils.isBlank(value)) {
return value;
}
return StringEscapeUtils.escapeHtml4(value);
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values == null) {
return values;
}
for (int i = 0; i < values.length; i++) {
values[i] = StringEscapeUtils.escapeHtml4(values[i]);
}
return values;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new LinkedHashMap<String, String[]>();
Map<String, String[]> parameterMap = super.getParameterMap();
if (parameterMap == null) {
return super.getParameterMap();
}
for (String key : parameterMap.keySet()) {
String[] values = parameterMap.get(key);
if (values != null && values.length > 0) {
for (int i = 0; i < values.length; i++) {
values[i] = StringEscapeUtils.escapeHtml4(values[i]);
}
}
map.put(key, values);
}
return map;
}
private void setRequestBody(InputStream stream) throws JsonMappingException, JsonProcessingException {
String line = "";
StringBuilder body = new StringBuilder();
// 读取POST提交的数据内容
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, Charset.forName(CHARSET)));
try {
while ((line = reader.readLine()) != null) {
body.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
mBody = body.toString();
if (StringUtils.isBlank(mBody)) {// 为空时,直接返回
return;
}
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.readValue(mBody, Map.class);
Map<String, Object> resultMap = new HashMap<>(map.size());
for (String key : map.keySet()) {
Object val = map.get(key);
if (map.get(key) instanceof String) {
resultMap.put(key, StringEscapeUtils.escapeHtml4(val.toString()));
} else {
resultMap.put(key, val);
}
}
mBody = objectMapper.writeValueAsString(resultMap);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (!JSON_TYPE.equalsIgnoreCase(super.getHeader(CONTENT_TYPE))) {// 非json类型,直接返回
return super.getInputStream();
}
if (StringUtils.isBlank(mBody)) {// 为空时,直接返回
return super.getInputStream();
}
final ByteArrayInputStream bais = new ByteArrayInputStream(mBody.getBytes(CHARSET));
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 listener) {
}
};
}
}
```
## 示例代码项目
* [https://github.com/osxm/websecurity_ency/tree/main/src/main/java/com/osxm/websecurity/xss](https://github.com/osxm/websecurity_ency/tree/main/src/main/java/com/osxm/websecurity/xss)
*****
*****
https://www.cnblogs.com/wangsongbai/p/15065001.html
- 空白目录
- 基本知识
- 数据与指令
- 漏洞扫描
- Coverity Scan
- 常见漏洞与处理措施
- Presentation Topic 1
- Preface
- 常见的软件缺陷与风险
- 安全漏洞相关概念(CVE,CNA, CWE,CVSS,OWASP)
- Web 安全漏洞发生的原因
- XSS(跨站脚本)攻击与预防
- CSRF-跨站点请求伪造
- SQL Inject
- 软件弱点预防之 —— Filesystem path, filename, or URI manipulation - 操控文件系统路径、文件名或 URI
- Improper Limitation of a Pathname to a Restricted Directory
- 点击劫持漏洞 Clickjacking
- Java Web安全风险应对
- Concludes
- SQL注入风险与防范措施
- SQL注入类型
- Sample
- XSS - 跨站脚本攻击
- 宽字节编码引发的XSS血案
- HTML与JavaScript 的自解码
- XSS Sample
- XSS 攻击载荷
- Cross-Site Scripting: 跨站脚本攻击 XSS
- XSS 与 CSRF
- 参考
- 解决示例
- CSRF-跨站请求伪造
- 基于Servlet 的Java Web项目的CSRF防御概念
- 基于JSP的Java Web项目的CSRF防御示例
- CSRF-跨站点请求伪造
- CSRF(跨站请求伪造)漏洞及解决方法
- Java Web应用CSRF防御攻略
- Spring Boot 项目使用Spring Security防护CSRF攻击实战
- 一次基于Coverity 扫描Spring Boot项目的CSRF弱点解决的探索之旅
- Coverity + CSRF
- Spring Boot CSRF攻击防御
- 文件上传漏洞
- 敏感信息泄露
- Filesystem path, filename, or URI manipulation -
- PATH_MANIPULATION+Coverity
- 防御方法
- Java漏洞及修复
- Java高风险弱点
- Java 防御XSS攻击实战与示例代码
- Java防御路径操作(Path Manipulation) 的正确姿势
- 示例
- 示例2
- Java之路径操纵解决的误区
- 结合Coverity扫描Spring Boot项目进行Path Manipulation漏洞修复
- Spring Boot实战项目之CSRF防御处理
- Java高风险弱点与修复之——SQL injection(SQL注入)
- Very weak password hashing (WEAK_PASSWORD_HASH)
- Insecure SSL/TLS: bad HostnameVerifier (BAD_CERT_VERIFICATION)
- 主机验证示例1
- Resource Leak
- Java中风险弱点
- Java代码弱点与修复之——Arguments in wrong order(参数顺序错误)
- Java代码弱点与修复之——ORM persistence error(对象关系映射持久错误)
- Java代码弱点与修复之——Logically dead code-逻辑死代码
- 示例1
- Java代码弱点与修复之——URL manipulation(URL操纵)
- Java代码弱点与修复之——Open redirect(开放式重定向)
- Spring项目Open Redirect漏洞解决
- Java代码弱点与修复之——Dereference null return value(间接引用空返回值)
- Java代码弱点与修复之——Dereference before null check 非空检查前间接引用
- Java代码弱点与修复之——Dereference after null check-空检查后间接引用
- Java代码弱点与修复之——Explicit null dereferenced(显式空间接引用)
- Java非空判断相关的弱点类型汇总与比较
- Java代码弱点与修复之——Copy-paste error(复制粘贴错误)
- Java代码弱点与修复之——Suspicious calls to generic collection methods
- Java代码弱点与修复之——Repeated conditional test(重复的条件测试)
- Java代码弱点与修复之——Masked Field(掩码字段)
- Spring Boot项目之伪Masked Field弱点解决
- Java代码弱点与修复之——STCAL: Static use of type Calendar or DateFormat
- Java代码弱点与修复之——RC: Questionable use of reference equality rather than calling equals
- Java代码弱点与修复之——Unintended regular expression(非期望的正则表达式)
- Java代码弱点与修复之——LI: Unsynchronized Lazy Initialization
- Java代码弱点与修复之——Risky cryptographic hashing function (RISKY_CRYPTO)
- 加密散列示例
- Java代码弱点与修复之——INT: Suspicious integer expression
- NP: Null pointer dereference
- SA: Useless self-operation
- Unguarded read
- SWL: Sleep with lock held
- Use of freed resources
- Stray semicolon
- UG: Unsynchronized get method, synchronized set method (FB.UG_SYNC_SET_UNSYNC_GET)
- Identical code for different branches
- RANGE: Range checks
- Infinite Loop
- Missing authorization check
- Java低风险弱点
- Java代码弱点与修复之——WMI: Inefficient Map Iterator(低效的Map迭代器)
- Java代码弱点与修复之——Dead local store(本地变量存储了闲置不用的对象)
- Java代码弱点与修复之——BC: Bad casts of object references(错误的强制类型转换)
- Java代码弱点与修复之——'Constant' variable guards dead code
- Java代码弱点与修复之——DE: Dropped or ignored exception(无视或忽略异常)
- Useless code - 无用的代码
- Dm: Dubious method used
- 字节转换
- Java代码弱点与修复之——Se: Incorrect definition of Serializable class(可序列化类的定义不正确)
- FS: Format string problem
- IM: Questionable integer math
- Information exposure to log file
- Insecure HTTP firewall
- NS: Suspicious use of non-short-circuit boolean operator
- REC: RuntimeException capture
- Resource leak on an exceptional path
- RV: Bad use of return value
- SBSC: String concatenation in loop using + operator
- SIC: Inner class could be made static
- SS: Unread field should be static
- UC: Useless code
- Unnecessary call to org.hibernate.Session.get method
- Unused value
- UPM: Private method is never called
- UrF: Unread field
- UuF: Unused field
- UwF: Unwritten field
- Audit
- Non-constant SQL
- Log injection (LOG_INJECTION)
- 日志漏洞示例1
- 实际场景
- URL
- 模板
- Web漏洞及修复
- Web开发
- 客户端请求地址
- Medium
- [Web缺陷与修复之]Property access or function call before check for null or undefined
- Bad use of null-like value
- Missing break in switch
- Logically dead code-JavaScript
- Identical code for different branches
- Expression with no effect
- Missing parentheses
- High
- Web之DOM-based cross-site scripting漏洞处理
- Summary
- Web基本知识
- 字符转义
- 工具
- Java静态分析工具之——SpogBugs
- FindBugs
- Synopsys Code Sight
- 使用Eclipse +SpotBugs 检测代码弱点