【漏洞三】跨站点脚本(XSS)攻击
【漏洞】
跨站点脚本(XSS)攻击
【原因】
跨站点脚本(也称为xss)是一个漏洞,攻击者可以发送恶意代码(通常在(Javascript的形式)给另一个用户。因为浏览器无法知道脚本是否值得信任,所以它将在用户上下文中执行脚本,从而允许攻击者访问任何cookie。
【解决】增加敏感脚本过滤器(转一篇整理较好的实现方案: https://blog.csdn.net/yucaifu1989/article/details/61616870)
使用filter过滤xss攻击,filter实现脚注入攻击过滤源码 。 先说一下实现思路:
1. 使用正则表达式的方式实现脚本过滤,这个方法准确率较高,但是可能根据不能的要求会变动;
2. 为了保证配置灵活(包括正则表达式灵活),使用xml配置文件的方式记录配置信息,配置信息包含是否开启校验、是否记录日志、是否中断请求、是否替换脚本字符等;
3. 为保证xml与正则表达式的特殊字符不冲突,使用<![CDATA[]]>标签存放正则表达式,但是在类中需要特殊处理;
4. 通过继承HttpRequestWrapper的方式实现request中header和parameter信息过滤;
5. xml解析使用dom4j,稍后会对这个工具的使用写一篇文章,暂时辛苦大家去网站查找资料
6. 使用XSSSecurityManager类实现配置信息加载和处理,XSSSecurityConfig记录匹配信息,XSSSecurityCon标识程序所需常量;
一共改了 7 个文件,如下:
1、XSSHttpRequestWrapper
package com.sg.security;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
/**
* @author winnie
* @date
* @describe request信息封装类,用于判断、处理request请求中特殊字符
*/
public class XSSHttpRequestWrapper extends HttpServletRequestWrapper {
/**
* 封装http请求
* @param request
*/
public XSSHttpRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
// 若开启特殊字符替换,对特殊字符进行替换
if(XSSSecurityConfig.REPLACE){
XSSSecurityManager.securityReplace(name);
}
return value;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
// 若开启特殊字符替换,对特殊字符进行替换
if(XSSSecurityConfig.REPLACE){
XSSSecurityManager.securityReplace(name);
}
return value;
}
/**
* 没有违规的数据,就返回false;
*
* @return
*/
@SuppressWarnings("unchecked")
private boolean checkHeader(){
Enumeration<String> headerParams = this.getHeaderNames();
while(headerParams.hasMoreElements()){
String headerName = headerParams.nextElement();
String headerValue = this.getHeader(headerName);
if(XSSSecurityManager.matches(headerValue)){
return true;
}
}
return false;
}
/**
* 没有违规的数据,就返回false;
*
* @return
*/
@SuppressWarnings("unchecked")
private boolean checkParameter(){
Map<String,Object> submitParams = this.getParameterMap();
Set<String> submitNames = submitParams.keySet();
for(String submitName : submitNames){
Object submitValues = submitParams.get(submitName);
if(submitValues instanceof String){
if(XSSSecurityManager.matches((String)submitValues)){
return true;
}
}else if(submitValues instanceof String[]){
for(String submitValue : (String[])submitValues){
if(XSSSecurityManager.matches((String)submitValue)){
return true;
}
}
}
}
return false;
}
/**
* 没有违规的数据,就返回false;
* 若存在违规数据,根据配置信息判断是否跳转到错误页面
* @param response
* @return
* @throws IOException
* @throws ServletException
*/
public boolean validateParameter(HttpServletResponse response) throws ServletException, IOException{
// 开始header校验,对header信息进行校验
if(XSSSecurityConfig.IS_CHECK_HEADER){
if(this.checkHeader()){
return true;
}
}
// 开始parameter校验,对parameter信息进行校验
if(XSSSecurityConfig.IS_CHECK_PARAMETER){
if(this.checkParameter()){
return true;
}
}
return false;
}
}
2、XSSSecurityFilter
package com.sg.security;
import java.io.IOException;
import javax.servlet.Filter;
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;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/**
* @author winnie
* @date
* @describe 安全信息审核类
*/
public class XSSSecurityFilter implements Filter{
private static Logger logger = Logger.getLogger(XSSSecurityFilter.class);
/**
* 销毁操作
*/
public void destroy() {
logger.info("XSSSecurityFilter destroy() begin");
XSSSecurityManager.destroy();
logger.info("XSSSecurityFilter destroy() end");
}
/**
* 安全审核
* 读取配置信息
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 判断是否使用HTTP
checkRequestResponse(request, response);
// 转型
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// http信息封装类
XSSHttpRequestWrapper xssRequest = new XSSHttpRequestWrapper(httpRequest);
// 对request信息进行封装并进行校验工作,若校验失败(含非法字符),根据配置信息进行日志记录和请求中断处理
if(xssRequest.validateParameter(httpResponse)){
if(XSSSecurityConfig.IS_LOG){
// 记录攻击访问日志
// 可使用数据库、日志、文件等方式
}
if(XSSSecurityConfig.IS_CHAIN){
httpRequest.getRequestDispatcher(XSSSecurityCon.FILTER_ERROR_PAGE).forward( httpRequest, httpResponse);
return;
}
}
chain.doFilter(xssRequest, response);
}
/**
* 初始化操作
*/
public void init(FilterConfig filterConfig) throws ServletException {
XSSSecurityManager.init(filterConfig);
}
/**
* 判断Request ,Response 类型
* @param request
* ServletRequest
* @param response
* ServletResponse
* @throws ServletException
*/
private void checkRequestResponse(ServletRequest request,
ServletResponse response) throws ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new ServletException("Can only process HttpServletRequest");
}
if (!(response instanceof HttpServletResponse)) {
throw new ServletException("Can only process HttpServletResponse");
}
}
}
3、XSSSecurityManager
package com.sg.security;
import java.util.Iterator;
import java.util.regex.Pattern;
import javax.servlet.FilterConfig;
import org.apache.log4j.Logger;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* @author winnie
* @date
* @describe 安全过滤配置管理类,由XSSSecurityManger修改
*/
public class XSSSecurityManager {
private static Logger logger = Logger.getLogger(XSSSecurityManager.class);
/**
* REGEX:校验正则表达式
*/
public static String REGEX;
/**
* 特殊字符匹配
*/
private static Pattern XSS_PATTERN ;
private XSSSecurityManager(){
//不可被实例化
}
public static void init(FilterConfig config){
logger.info("XSSSecurityManager init(FilterConfig config) begin");
//初始化过滤配置文件
String xssPath = config.getServletContext().getRealPath("/")
+ config.getInitParameter("securityconfig");
// 初始化安全过滤配置
try {
if(initConfig(xssPath)){
// 生成匹配器
XSS_PATTERN = Pattern.compile(REGEX);
}
} catch (DocumentException e) {
logger.error("安全过滤配置文件xss_security_config.xml加载异常",e);
}
logger.info("XSSSecurityManager init(FilterConfig config) end");
}
/**
* 读取安全审核配置文件xss_security_config.xml
* 设置XSSSecurityConfig配置信息
* @param path 配置文件地址 eg C:/apache-tomcat-6.0.33/webapps/security_filter/WebRoot/config/xss/xss_security_config.xml
* @return
* @throws DocumentException
*/
@SuppressWarnings("unchecked")
public static boolean initConfig(String path) throws DocumentException {
logger.info("XSSSecurityManager.initConfig(String path) begin");
Element superElement = new SAXReader().read(path).getRootElement();
XSSSecurityConfig.IS_CHECK_HEADER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_HEADER));
XSSSecurityConfig.IS_CHECK_PARAMETER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_PARAMETER));
XSSSecurityConfig.IS_LOG = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_LOG));
XSSSecurityConfig.IS_CHAIN = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHAIN));
XSSSecurityConfig.REPLACE = new Boolean(getEleValue(superElement,XSSSecurityCon.REPLACE));
Element regexEle = superElement.element(XSSSecurityCon.REGEX_LIST);
if(regexEle != null){
Iterator<Element> regexIt = regexEle.elementIterator();
StringBuffer tempStr = new StringBuffer("^");
//xml的cdata标签传输数据时,会默认在\前加\,需要将\\替换为\
while(regexIt.hasNext()){
Element regex = (Element)regexIt.next();
String tmp = regex.getText();
tmp = tmp.replaceAll("\\\\\\\\", "\\\\");
tempStr.append(tmp);
tempStr.append("|");
}
if(tempStr.charAt(tempStr.length()-1)=='|'){
REGEX= tempStr.substring(0, tempStr.length()-1)+"$";
logger.info("安全匹配规则"+REGEX);
}else{
logger.error("安全过滤配置文件加载失败:正则表达式异常 "+tempStr.toString());
return false;
}
}else{
logger.error("安全过滤配置文件中没有 "+XSSSecurityCon.REGEX_LIST+" 属性");
return false;
}
logger.info("XSSSecurityManager.initConfig(String path) end");
return true;
}
/**
* 从目标element中获取指定标签信息,若找不到该标签,记录错误日志
* @param element 目标节点
* @param tagName 制定标签
* @return
*/
private static String getEleValue(Element element, String tagName){
if (isNullStr(element.elementText(tagName))){
logger.error("安全过滤配置文件中没有 "+XSSSecurityCon.REGEX_LIST+" 属性");
}
return element.elementText(tagName);
}
/**
* 对非法字符进行替换
* @param text
* @return
*/
public static String securityReplace(String text){
if(isNullStr(text)){
return text;
}else{
return text.replaceAll(REGEX, XSSSecurityCon.REPLACEMENT);
}
}
/**
* 匹配字符是否含特殊字符
* @param text
* @return
*/
public static boolean matches(String text){
if(text==null){
return false;
}
return XSS_PATTERN.matcher(text).matches();
}
/**
* 释放关键信息
*/
public static void destroy(){
logger.info("XSSSecurityManager.destroy() begin");
XSS_PATTERN = null;
REGEX = null;
logger.info("XSSSecurityManager.destroy() end");
}
/**
* 判断是否为空串,建议放到某个工具类中
* @param value
* @return
*/
public static boolean isNullStr(String value){
return value == null || value.trim().equals("");
}
}
4、 XSSSecurityConfig
package com.sg.security;
/**
* @author winnie
* 安全过滤配置信息类
*/
public class XSSSecurityConfig {
/**
* CHECK_HEADER:是否开启header校验
*/
public static boolean IS_CHECK_HEADER;
/**
* CHECK_PARAMETER:是否开启parameter校验
*/
public static boolean IS_CHECK_PARAMETER;
/**
* IS_LOG:是否记录日志
*/
public static boolean IS_LOG;
/**
* IS_LOG:是否中断操作
*/
public static boolean IS_CHAIN;
/**
* REPLACE:是否开启替换
*/
public static boolean REPLACE;
}
5、XSSSecurityCon
package com.sg.security;
/**
* @author winnie
* @date
* @describe
*/
public class XSSSecurityCon {
/**
* 配置文件标签 isCheckHeader
*/
public static String IS_CHECK_HEADER = "isCheckHeader";
/**
* 配置文件标签 isCheckParameter
*/
public static String IS_CHECK_PARAMETER = "isCheckParameter";
/**
* 配置文件标签 isLog
*/
public static String IS_LOG = "isLog";
/**
* 配置文件标签 isChain
*/
public static String IS_CHAIN = "isChain";
/**
* 配置文件标签 replace
*/
public static String REPLACE = "replace";
/**
* 配置文件标签 regexList
*/
public static String REGEX_LIST = "regexList";
/**
* 替换非法字符的字符串
*/
public static String REPLACEMENT = "";
/**
* FILTER_ERROR_PAGE:过滤后错误页面
*/
public static String FILTER_ERROR_PAGE = "/common/filtererror.jsp";
}
6、xss_security_config.xml
<?xml version="1.0" encoding="UTF-8"?>
<XSSConfig>
<!-- 是否进行header校验 -->
<isCheckHeader>false</isCheckHeader>
<!-- 是否进行parameter校验 -->
<isCheckParameter>true</isCheckParameter>
<!-- 是否记录日志 -->
<isLog>true</isLog>
<!-- 是否中断请求 -->
<isChain>false</isChain>
<!-- 是否开启特殊字符替换 -->
<replace>true</replace>
<!-- 是否开启特殊url校验 -->
<isCheckUrl>true</isCheckUrl>
<regexList>
<!-- 匹配含有字符: alert( ) -->
<regex><![CDATA[.*[A|a][L|l][E|e][R|r][T|t]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: window.location = -->
<regex><![CDATA[.*[W|w][I|i][N|n][D|d][O|o][W|w]\\.[L|l][O|o][C|c][A|a][T|t][I|i][O|o][N|n]\\s*=.*]]></regex>
<!-- 匹配含有字符:style = x:ex pression ( ) -->
<regex><![CDATA[.*[S|s][T|t][Y|y][L|l][E|e]\\s*=.*[X|x]:[E|e][X|x].*[P|p][R|r][E|e][S|s]{1,2}[I|i][O|o][N|n]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: document.cookie -->
<regex><![CDATA[.*[D|d][O|o][C|c][U|u][M|m][E|e][N|n][T|t]\\.[C|c][O|o]{2}[K|k][I|i][E|e].*]]></regex>
<!-- 匹配含有字符: eval( ) -->
<regex><![CDATA[.*[E|e][V|v][A|a][L|l]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: unescape() -->
<regex><![CDATA[.*[U|u][N|n][E|e][S|s][C|c][A|a][P|p][E|e]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: execscript( ) -->
<regex><![CDATA[.*[E|e][X|x][E|e][C|c][S|s][C|c][R|r][I|i][P|p][T|t]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: msgbox( ) -->
<regex><![CDATA[.*[M|m][S|s][G|g][B|b][O|o][X|x]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: confirm( ) -->
<regex><![CDATA[.*[C|c][O|o][N|n][F|f][I|i][R|r][M|m]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: prompt( ) -->
<regex><![CDATA[.*[P|p][R|r][O|o][M|m][P|p][T|t]\\s*\\(.*\\).*]]></regex>
<!-- 匹配含有字符: <script> </script> -->
<regex><![CDATA[.*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>.*]]></regex>
<!-- 匹配含有字符: 含有一个符号: " -->
<regex><![CDATA[[.&[^\"]]*\"[.&[^\"]]*]]></regex>
<!-- 匹配含有字符: 含有一个符号: ' -->
<regex><![CDATA[[.&[^']]*'[.&[^']]*]]></regex>
<!-- 匹配含有字符: 含有回车换行 和 <script> </script> -->
<regex><![CDATA[[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*]]></regex>
</regexList>
</XSSConfig>
7、web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 信息安全审核 -->
<filter>
<filter-name>XSSFiler</filter-name>
<filter-class>
com.sg.security.XSSSecurityFilter
</filter-class>
<init-param>
<param-name>securityconfig</param-name>
<param-value>
/WebRoot/config/xss/xss_security_config.xml
</param-value>
</init-param>
</filter>
<!-- 拦截请求类型 -->
<filter-mapping>
<filter-name>XSSFiler</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>XSSFiler</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
</web-app>
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- <!-- 信息安全审核 -->
- <filter>
- <filter-name>XSSFiler</filter-name>
- <filter-class>
- com.sg.security.XSSSecurityFilter
- </filter-class>
- <init-param>
- <param-name>securityconfig</param-name>
- <param-value>
- /WebRoot/config/xss/xss_security_config.xml
- </param-value>
- </init-param>
- </filter>
- <!-- 拦截请求类型 -->
- <filter-mapping>
- <filter-name>XSSFiler</filter-name>
- <url-pattern>*.jsp</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>XSSFiler</filter-name>
- <url-pattern>*.do</url-pattern>
- </filter-mapping>
- </web-app>
【漏洞三】跨站点脚本(XSS)攻击的更多相关文章
- 跨站点脚本编制-XSS 描述及解决方法
跨站点脚本编制可能是一个危险的安全性问题,在设计安全的基于 Web 的应用程序时应该考虑这一点.本文中,描述了这种问题的本质.它是如何起作用的,并概述了一些推荐的修正策略. 当今的大多数网站都对 We ...
- 跨站点脚本编制实例(AppScan扫描结果)
最近工作要求解决下web的项目的漏洞问题,扫描漏洞是用的AppScan工具,其中有很多是关于跨站点脚本编制问题的.下面就把这块东西分享出来. 原创文章,转载请注明 ------------------ ...
- ASP.NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 (XSS)
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...
- 跨站点脚本攻击XSS
来源:http://www.freebuf.com/articles/web/15188.html 跨站点脚本攻击是一种Web应用程序的攻击,攻击者尝试注入恶意脚本代码到受信任的网站上执行恶意操作.在 ...
- IBM Rational AppScan:跨站点脚本攻击深入解析
IBM Rational AppScan:跨站点脚本攻击深入解析 了解黑客如何启动跨站点脚本攻击(cross-site scripting,XSS),该攻击危害(及不危害)什么,如何检测它们,以 ...
- 跨站点脚本编制 - SpringBoot配置XSS过滤器(基于mica-xss)
1. 简介 XSS,即跨站脚本编制,英文为Cross Site Scripting.为了和CSS区分,命名为XSS. XSS是最普遍的Web应用安全漏洞.这类漏洞能够使得攻击者嵌入恶意脚本代码 ...
- 网站跨站点脚本,Sql注入等攻击的处理
从360安全论坛里找到的一段代码,经过整理封装,直接在站点Global.asax文件或写一个HttpModule来拦截恶意请求即可: http://bbs.webscan.360.cn/forum.p ...
- [原]网站跨站点脚本,Sql注入等攻击的处理
从360安全论坛里找到的一段代码,经过整理封装,直接在站点Global.asax文件或写一个HttpModule来拦截恶意请求即可: http://bbs.webscan.360.cn/forum.p ...
- 跨站点脚本编制 - SpringBoot配置XSS过滤器(基于Jsoup)
1. 跨站点脚本编制 风险:可能会窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查看或变更用户记录以及执行事务. 原因:未对用户输入正确执行危险字符清 ...
随机推荐
- [安卓基础]011存储数据(中)——sqlite语法介绍
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- 【Kafka】知识总结
Kafka是什么? Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据. Kafka架构 1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除) 点对 ...
- ASP.NET通过EntityFramework CodeFirst创建数据库
Number1 新建一个项目 给新项目添加一个实体数据模型 选择第三个 这里我创建两个有关系的类,也就是有外键关系的数据库表 using System; using System.Collection ...
- Java实现 蓝桥杯 算法训练 天数计算
试题 算法训练 天数计算 问题描述 编写函数求某年某月某日(**** ** **)是这一年的第几天 .提示:要考虑闰年,闰年的2月是29天(闰年的条件:是4的倍数但不是100的倍数,或者是400的倍数 ...
- Java实现 LeetCode 680 验证回文字符串 Ⅱ(暴力)
680. 验证回文字符串 Ⅱ 给定一个非空字符串 s,最多删除一个字符.判断是否能成为回文字符串. 示例 1: 输入: "aba" 输出: True 示例 2: 输入: " ...
- Java实现 蓝桥杯 算法提高 复数四则运算
算法提高 6-17复数四则运算 时间限制:1.0s 内存限制:512.0MB 提交此题 设计复数库,实现基本的复数加减乘除运算. 输入时只需分别键入实部和虚部,以空格分割,两个复数之间用运算符分隔:输 ...
- Java实现蓝桥杯七对数字
今有7对数字:两个1,两个2,两个3,-两个7,把它们排成一行. 要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字.如下就是一个符合要求的排列: 1712642 ...
- java实现第三届蓝桥杯火柴游戏
火柴游戏 [编程题](满分34分) 这是一个纵横火柴棒游戏.如图[1.jpg],在3x4的格子中,游戏的双方轮流放置火柴棒.其规则是: 不能放置在已经放置火柴棒的地方(即只能在空格中放置). 火柴棒的 ...
- Spring AOP 扫盲
关于AOP 面向切面编程(Aspect-oriented Programming,俗称AOP)提供了一种面向对象编程(Object-oriented Programming,俗称OOP)的补充,面向对 ...
- chattr +i 用户也没法随意删除
root用户也没法用rm随意删除文件? 前言 在你的印象中,是不是root用户就可以为所欲为呢?随便一个rm -rf *,一波骚操作走人?可能没那么容易. 先来个示例,创建一个文本文件test.t ...