跨站脚本攻击XSS是指攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被解析执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!
存储型XSS: 存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie

反射型XSS: 非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面

DOM型XSS: 不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。
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编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${}”这样的参数格式,所以,这样的参数需要我们在代码中手工进行处理来防止注入。
话不多说,上代码
Spring Boot 基础就不介绍了,推荐看这个免费教程:
对于Xss攻击和Sql注入,我们可以通过过滤器来搞定,可根据业务需要排除部分请求
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最新版)
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
觉得不错,别忘了随手点赞+转发哦!
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem
啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组
基本上,我只是试图在满足特定条件时停止程序运行其余行。unlessraw_information.firstputs"Noresultswerereturnedforthatquery"breakend然而,在程序运行之前我得到了这个错误:Invalidbreakcompileerror(SyntaxError)执行此操作的正确方法是什么? 最佳答案 abort("Noresultswerereturnedforthatquery")unlesscondition或unlessconditionabort("Noresultswer
如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题: