CSRF攻击与XSS攻击,怎么防御 @by_TWJ

CSRF攻击

前言

CSRF与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
XSS是通过插入恶意的攻击脚本到用户信任的网站,代码被前端解析后,请求服务器。
CSRF是伪装成用户信任的网站发起请求到服务器。
CSRF攻击不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

基于Session方式

Csrf 伪造登录网址盗取用户密码(Form表单方式的csrf)

详细:黑客发送伪造的链接给用户点击,用户点击后,以为是真正的网站,所以进行登录操作,输入了用户名和密码。
具体模拟:
1、首先真正的网站有个登录校验的POST请求,例如: POST http://www.xxxx.com/login 这里是登录校验请求,传参格式为Form表单。
2、新建一个html文件,包含登录功能,但登录校验功能使用真正的网站的请求 。
3、黑客把html文件做成一个网站,然后发送网站路径给A用户
4、A用户点击后,就会跳转到伪造网站,接着让用户输入用户名和密码,发送给真正的网站校验。
5、这样的后果是,导致用户在不知情的情况下泄露了用户名和密码。这是不可知的操作,是很危险的。

伪造测试页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>csrf 测试攻击类</title>
</head>
<body>
<h1>伪造登录界面</h1>

<form action="http://127.0.0.1:8091/login" method="post">
    <div>
        <!--name必须为“username"-->
        <input type="text" name="username" placeholder="用户名"/>
    </div>
    <div>
        <!--name必须为"password"-->
        <input type="password" name="password" placeholder="密码"/>
    </div>
    <input type="submit" value="登录"/>
   
</form>

</body>
</html>

解决办法:

方案一、

  1. 添加限制跨域访问,非允许的网站的资源不可访问,这样就可以限制了,在伪造网址里使用 js方式调用请求。
  2. 使用csrf令牌,对Form表单进一步保护。因为第三方网站可以通过form表单提交,跳过 js/限制跨域访问方式,来请求,所以我们需要一个表单参数csrf令牌,来防御csrf攻击。具体在所有form表单里添加 csrf令牌 表单参数,然后后台验证csrf令牌是否合法,这个csrf令牌是由服务端生成的。

方案二、

  1. 添加限制跨域访问
  2. 我们也可以使用Referer验证的方式,来防御csrf攻击。

csrf 伪造网址,让用户在不知情的情况下新增数据。(直接网址拼接方式的csrf)

详细:黑客发送伪造的链接给用户点击,用户点击后,后台新增了一条数据。
具体模拟:
1、首先真正的网站有个新增的GET请求,例如:GET http://www.xxxx.com/order/add?details=1,2,3,4 这里的意思是,把这几个商品加入到订单里。
2、新建一个html文件,包含内容 <script>location.href=“http://www.xxxx.com/order/add?details=1,2,3,4”</script>
3、黑客把html文件做成一个网站,然后发送网站路径给A用户
4、A用户点击后,就会跳转到伪造网站,接着伪造网站就会把参数信息带上,发送给真正的网站。
5、这样的后果是,导致用户在不知情的情况下新增了订单。这是不可知的操作,是很危险的。

解决办法:

方案一、

  1. 避免使用GET请求做一些操作数据库的动作。
  2. 添加限制跨域访问
  3. 使用csrf令牌,对Form表单进一步保护,防止伪造网站使用 Form表单方式跳转页面。
  4. 尽量少用Form表单,Form表单方式请求,可以越过跨域访问,导致第三方可以使用Form表单,所以Form表单不安全。若用Form表单,则都需要添加csrf令牌。

方案二、

  1. 避免使用GET请求做一些操作数据库的动作。
  2. 添加限制跨域访问
  3. 使用Referer验证的方式,来防御csrf攻击。

基于Jwt方式

为什么Jwt没有csrf问题

因为Jwt是 基于js的方式请求的,所以我们只需要添加限制跨域访问 ,就可以预防csrf问题。

jwt也不存在Form表单问题。Jwt不走“在游览器直接访问”这条路的,所有Form表单都是在js完成的。js又被限制跨域访问所限制,只能访问允许的。

jwt:若黑客故意走“在游览器直接访问”这条路,这时,黑客就需要知道token了,因为jwt不会像session一样,用户点击链接,游览器自动帮用户加上jsessionId。黑客需要手动添加token信息,但黑客不知道,所以使用jwt安全。

jwt就像csrf令牌,自带验证。

术语

跨域访问限制

安全系数:★★★★★
跨域访问限制可以阻止第三方使用js调用我们网站请求

CSRF令牌

安全系数:★★★★★

CSRF令牌:为每个用户会话生成唯一的CSRF令牌,并将该令牌添加到所有请求中。这样,即使攻击者能够窃取用户的会话ID,但由于缺乏正确的CSRF令牌,他们也无法成功执行CSRF攻击。
在这里插入图片描述

Referer验证

安全系数:★★★★

在这里插入图片描述
Referer SDK

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
        Exception {
    logger.debug("拦截器拦截到对:{}的访问", request.getRequestURI());
    String referer = request.getHeader("referer");
    logger.debug("referer:{}", referer);
    StringBuilder sb = new StringBuilder();
    sb.append(request.getScheme()).append("://").append(request.getServerName());
    logger.debug("basePath:{}", sb.toString());
    if (referer == null || referer == "" || !referer.startsWith(sb.toString())) {
        response.setContentType("text/plain; charset=utf-8");
                response.getWriter().write("非法访问,请通过页面正常问!");
        return false;
    }
    return true;
}

参考文章:https://blog.csdn.net/qq_37432174/article/details/128001627

疑问答辩

Form表单提交为什么会有csrf攻击问题

由于第三方网站可以使用Form表单提交方式向网站发送请求,并且没有跨域问题。这样第三方就可以利用这个漏洞请求我们网站,进行操作。

扩展:
为什么form表单提交没有跨域问题,但ajax提交有跨域问题?

这里有个例子:

  1. 页面Form表单提交
    这个没有跨域问题
<form action="http://127.0.0.1:8091/login" method="post">
    <div>
        <!--name必须为“username"-->
        <input type="text" name="username" placeholder="用户名"/>
    </div>
    <div>
        <!--name必须为"password"-->
        <input type="password" name="password" placeholder="密码"/>
    </div>
    <input type="submit" value="登录"/>

</form>

警告:我觉得是这个Form元素有问题,但凡是用Form,都能跳过跨域拦截。Form支持的传输格式有application/x-www-form-urlencoded、multipart/form-data、text/plain。所以你们要注意点这几个请求方式,都存在CSRF问题,跨域是解决不了的,需要使用csrf令牌或者Referer解决。

  1. js Form表单提交
    这个有跨域问题
<button id="test2">测试js方式,提交Form表单</button>
document.getElementById('test2').onclick = function(){
    const formData = new FormData();
    formData.set('username','admin')
    formData.set('password','admin2')
    
    axios.post('http://127.0.0.1:8091/login',formData,{headers: {
      'Content-Type': 'multipart/form-data'
    }}).then(res=>{
        console.log(res)
    })
}

参考文章:为什么form表单提交没有跨域问题,但ajax提交有跨域问题?

结论

  1. 跨域访问限制可以解决90%的问题。

  2. 剩下10%,是GET请求和Form表单提交导致的,这两个留了一个有漏洞的口子。

    • GET请求:所以我们GET请求只用来做查询操作,防御CSRF攻击
    • Form表单:“Form表单提交”支持这三种格式,所以这三种才会有漏洞:application/x-www-form-urlencoded、multipart/form-data、text/plain
      解决方法一: Form表单使用csrf令牌,防御CSRF攻击。
      解决方法二: Form表单使用Referer验证,防御CSRF攻击
      注意:因为我们使用Form表单请求都是添加或修改操作,建议使用POST请求

XSS攻击

前言

CSRF与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
XSS是通过插入恶意的攻击脚本到用户信任的网站,代码被前端解析后,请求服务器。
CSRF是伪装成用户信任的网站发起请求到服务器。
CSRF攻击不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

XSS
跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。在不同场景下,XSS有相应不同的表现形式,主要分为反射型存储型以及DOM型的跨站脚本攻击,所造成的影响主要是窃取用户登录凭证(Cookies)、挂马攻击、页面访问挟持等。

类型

存储型

这种攻击多见于论坛、博客和留言板,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入帖子的内容中。随着帖子被服务器存储下来,恶意脚本也永久地被存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意

通过保存html元素到数据库字段里,字段在页面展示时,没有对字段进行编码,导致游览器以为是html元素,然后直接解析元素,导致数据库字段里的html元素可以操纵页面。

在这里插入图片描述

解决办法:

  1. 展示方面优化:
    • 对数据库字段里的html元素进行编码后在展示。
    • 使用安全的API:在修改DOM时,使用安全的API来操作DOM元素。避免使用innerHTML等易受攻击的API,而是使用textContent或setAttribute等更安全的方法。
  2. 保存字段方面优化:过滤脚本元素

反射型

攻击者通过电子邮件等方式将包含XSS代码的恶意链接发送给目标用户。当目标用户访问该链接时,服务器接收该目标用户的请求并进行处理,然后服务器把带有XSS代码的数据发送给目标用户的浏览器,浏览器解析这段带有XSS代码的恶意脚本后,就会触发XSS漏洞

是通过URL参数直接注入,一般是使用alert来探测站点是否防御,直接攻击的使用src来引入自己的脚本

例如:

  1. 在参数中注入script脚本
http://localhost:1521/?from=<script>alert(1)</script>bing
  1. 页面访问时直接使用参数,导致脚本执行

<div>${from}</div>

解决办法:

  1. 展示方面优化:
    • 对数据库字段里的html元素进行编码后在展示。
    • 使用安全的API:在修改DOM时,使用安全的API来操作DOM元素。避免使用innerHTML等易受攻击的API,而是使用textContent或setAttribute等更安全的方法。
  2. 传参参数字段方面优化:过滤脚本元素
  3. 使用Content Security Policy(CSP 内容安全策略),限制主动访问外部资源(例如限制引入外部第三方 js)

DOM型

攻击者通过修改网页的DOM结构来实施攻击,当用户浏览网页时,恶意脚本会被执行。

DOM型xss和别的xss最大的区别就是,反射型是打开就会执行,DOM型是用户点击该链接时触发。

反射型就像一个是导弹,到达目的地就爆炸,另一个DOM型就像地雷,等待人去踩。

模拟注入DOM对象,点击DOM对象,就会执行一系列操作。

例如:

  1. 这里点击DOM就会跳转新页面。
<body>
<!-- value = <a href="https://blog.csdn.net/" target="_blank">点击</a> -->
<input type="text" name="node" value="" style="width:300px;"> <button id="btn1">添加</button>

<div>
    <div>输入值:<div id="content"></div></div>
</div>
<script>
    document.getElementById('btn1').onclick = function(){
        let input = document.querySelector('input[name="node"]')
        document.getElementById('content').innerHTML = input.value
    }
</script>
  1. 这里下方有个点击按钮,点击就会跳转新页面。
    在这里插入图片描述
    注意:他们可能还会注入第三方的脚本文件

解决方法:

  1. 展示方面优化:
    • 对数据库字段里的html元素进行编码后在展示。
    • 使用安全的API:在修改DOM时,使用安全的API来操作DOM元素。避免使用innerHTML等易受攻击的API,而是使用textContent或setAttribute等更安全的方法。
  2. 传参参数字段方面优化:过滤脚本元素
  3. 使用Content Security Policy(CSP 内容安全策略),限制主动访问外部资源(例如限制引入外部第三方 js)

总结

最终解决办法:

  1. 展示方面优化
    • 对数据库字段里的html元素进行编码后在展示。
    • 使用安全的API:在修改DOM时,使用安全的API来操作DOM元素。避免使用innerHTML等易受攻击的API,而是使用textContent或setAttribute等更安全的方法。
  2. 保存字段方面优化:过滤脚本元素
  3. 传参参数字段方面优化:过滤脚本元素
  4. 使用Content Security Policy(CSP 内容安全策略),限制主动访问外部资源(例如限制引入外部第三方 js)

具体可实现解决:

  1. 展示方面优化
    • 前端一般使用vue等框架,所以,它们已经帮我们处理好了,我们不用管。
  2. 使用Content Security Policy(CSP 内容安全策略)
    • spring-security 提供了csp sdk,我们只需要配置一下就好了。

剩余的:

在特定情况下,可以忽略,例如使用vue等框架展示字段。

  1. 保存字段方面优化:过滤脚本元素
    • 这个可以忽略,只要展示方面做好优化,就不会出问题了。
  2. 传参参数字段方面优化:过滤脚本元素
    • 传参字段不能直接解析到页面,现在都前后端分离了,前端都使用vue等框架,传参等字段都会先通过vue等框架展示,所以也不需要我们去处理。

spring-security CSP SDK

参考文章:https://springdoc.cn/spring-security-csp/

@Configuration
public class ContentSecurityPolicySecurityConfiguration {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.headers()
            .xssProtection()
            .and()
            .contentSecurityPolicy("form-action 'self'");
        return http.build();
    }
}
  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值