使用java如何解决XSS攻击?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
Java的特点有哪些 1.Java语言作为静态面向对象编程语言的代表,实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。 2.Java具有简单性、面向对象、分布式、安全性、平台独立与可移植性、动态性等特点。 3.使用Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容
简单说就是说,通过在输入框输入一些js代码,如在账号密码输入框中输入
<video src=1 onerror=alert(/xss/)/>
或者
<script>alert("@@") </script>
这样点击提交的时候就会触发alert弹窗,分别弹出 xss 和 @@ 的内容,这里只是做个简单的演示,弹了个窗口,还能存储病毒下载地址到服务端,进入的时候自动下载,或者修改你的cookie啥的,这里感兴趣可以百度查查xss攻击
这是一种相对容易理解的方式,解决思路就是,当恶意注入的字段中,包含了类似<script>alert(ooo)</script>
这种html标签时,后台程序代码中强制替换或更改标签内容,这样存入数据库的内容再次返回至页面时,就不会以html的形式进行执行了
下面提供一个工具类
/**
* xss特殊字符拦截与过滤
*
* @author zhangcy
* @date 2021-04016
*/
public class XssStrUtils {
/**
* 滤除content中的危险 HTML 代码, 主要是脚本代码, 滚动字幕代码以及脚本事件处理代码
* @param content 需要滤除的字符串
* @return 过滤的结果
*/
public static String replaceHtmlCode(String content) {
if (null == content) return null;
if (0 == content.length()) return "";
// 需要滤除的脚本事件关键字
String[] eventKeywords = {
"onmouseover", "onmouseout", "onmousedown", "onmouseup", "onmousemove", "onclick", "ondblclick",
"onkeypress", "onkeydown", "onkeyup", "ondragstart", "onerrorupdate", "onhelp", "onreadystatechange",
"onrowenter", "onrowexit", "onselectstart", "onload", "onunload", "onbeforeunload", "onblur",
"onerror", "onfocus", "onresize", "onscroll", "oncontextmenu", "alert"
};
content = replace(content, "<script", "<script", false);
content = replace(content, "</script", "</script", false);
content = replace(content, "<marquee", "<marquee", false);
content = replace(content, "</marquee", "</marquee", false);
content = replace(content, "'", "_", false);// 将单引号替换成下划线
content = replace(content, "\"", "_", false);// 将双引号替换成下划线
// 滤除脚本事件代码
for (int i = 0; i < eventKeywords.length; i++) {
content = replace(content, eventKeywords[i], "_" + eventKeywords[i], false); // 添加一个"_", 使事件代码无效
}
return content;
}
/**
* 将字符串 source 中的 oldStr 替换为 newStr, 并以大小写敏感方式进行查找
*
* @param source 需要替换的源字符串
* @param oldStr 需要被替换的老字符串
* @param newStr 替换为的新字符串
*/
private static String replace(String source, String oldStr, String newStr) {
return replace(source, oldStr, newStr, true);
}
/**
* 将字符串 source 中的 oldStr 替换为 newStr, matchCase 为是否设置大小写敏感查找
*
* @param source 需要替换的源字符串
* @param oldStr 需要被替换的老字符串
* @param newStr 替换为的新字符串
* @param matchCase 是否需要按照大小写敏感方式查找
*/
private static String replace(String source, String oldStr, String newStr,boolean matchCase) {
if (source == null) return null;
// 首先检查旧字符串是否存在, 不存在就不进行替换
if (source.toLowerCase().indexOf(oldStr.toLowerCase()) == -1) return source;
int findStartPos = 0;
int a = 0;
while (a > -1) {
int b = 0;
String str1, str2, str3, str4, strA, strB;
str1 = source;
str2 = str1.toLowerCase();
str3 = oldStr;
str4 = str3.toLowerCase();
if (matchCase) {
strA = str1;
strB = str3;
} else {
strA = str2;
strB = str4;
}
a = strA.indexOf(strB, findStartPos);
if (a > -1) {
b = oldStr.length();
findStartPos = a + b;
StringBuffer bbuf = new StringBuffer(source);
source = bbuf.replace(a, a + b, newStr) + "";
// 新的查找开始点位于替换后的字符串的结尾
findStartPos = findStartPos + newStr.length() - b;
}
}
return source;
}
}
我们用一个实际的接口做一下简单的测试
@PostMapping("/getAccName")
public String getAccName(@RequestBody NameParams params){
String s = XssStrUtils.replaceHtmlCode(params.getName());
return s;
}
使用接口工具调一下,
使用这种方式,即使前端恶意注入了某些非法的html标签,经过后端的过滤处理,返回的内容就不会执行html的相关操作事件了
第二种思路,考虑在过滤器中添加对所有请求接口的参数进行参数的拦截过滤,即程序认为的不合法标签都会自动做过滤,至于过滤的规则,可以借助现有的第三方组件,比如spring框架的htmlUtil类,这里使用hutool工具集提供的相关API做处理
导入依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.9</version>
</dependency>
1、添加自定义过滤器增强包装类
public class XssHttpRequestWrapper extends HttpServletRequestWrapper {
public XssHttpRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if(!StringUtils.isEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if(values!=null){
for(int i=0;i<values.length;i++){
String value = values[i];
if(!StringUtils.isEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i]=value;
}
}
return values;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> parameters = super.getParameterMap();
Map<String, String[]> map = new LinkedHashMap<>();
if(parameters !=null){
for(String key : parameters.keySet()){
String[] values = parameters.get(key);
for(int i=0;i<values.length;i++){
String value = values[i];
if(!StringUtils.isEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i]=value;
}
map.put(key,values);
}
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if(!StringUtils.isEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream in = super.getInputStream();
InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
BufferedReader buffer = new BufferedReader(reader);
StringBuffer body = new StringBuffer();
String line = buffer.readLine();
while (line !=null){
body.append(line);
line = buffer.readLine();
}
buffer.close();
reader.close();
in.close();
Map<String,Object> map = JSONUtil.parseObj(body.toString());
Map<String,Object> result = new LinkedHashMap<>();
for(String key : map.keySet()){
Object val = map.get(key);
if(val instanceof String){
if(!StringUtils.isEmpty(val.toString())){
result.put(key,HtmlUtil.filter(val.toString()));
}
}else {
result.put(key,val);
}
}
String json = JSONUtil.toJsonStr(result);
ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bain.read();
}
};
}
}
可以理解为,在自定义过滤器中添加上面的增强类,那么所有请求后端的接口都将先走改类的逻辑,参数进行过滤
2、自定义过滤器并注入全局bean
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);
filterChain.doFilter(requestWrapper,servletResponse);
}
@Override
public void destroy() {
}
}
@Configuration
public class XSSFilterRegister {
@Bean
public FilterRegistrationBean<XssFilter> RegistTest1(){
//通过FilterRegistrationBean实例设置优先级可以生效
FilterRegistrationBean<XssFilter> bean = new FilterRegistrationBean<XssFilter>();
bean.setFilter(new XssFilter());//注册自定义过滤器
bean.setName("flilter");//过滤器名称
bean.addUrlPatterns("/*");//过滤所有路径
return bean;
}
}
仍然使用上面的接口做一下测试
@PostMapping("/getAccName")
public String getAccName(@RequestBody NameParams params){
return "name is : "+ params.getName();
}
看完上述内容,你们掌握使用java如何解决XSS攻击的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。