xss攻击和csrf攻击实现方式及预防

235 阅读5分钟

xss:(Cross-site scripting)

跨站脚本攻击。恶意攻击者在web页面中会插入一些恶意的script代码。当用户浏览该页面的时候,那么嵌入到web页面中script代码会执行,因此会达到恶意攻击用户的目的。

分类:

1.反射型xss

2.存储型xss

3.dom型

危害:

盗取用户登录凭证(Cookie)、劫持用户会话、修改网页内容、网页挂马、恶意重定向、Dos攻击、钓鱼攻击、XSS蠕虫攻击等

反射型xss:

  1. 恶意用户分享了一个正常网站的链接,链接中带有恶意内容
  2. 正常用户点击了该链接
  3. 服务器在不知情的情况,把链接的恶意内容读取了出来,放进了页面中,让正常用户遭到攻击

比如:

www.baidu.com/search=<script>alert('1')</script>

(或者某个表单输入)服务器不经过处理,直接返回给客户端,客户端页面会执行aler t('1')

  • 如何防范:
  1. 设置http请求头;使用csp (内容安全策略)等http头部来限制哪些资源可以加载和执行。csp可以帮助阻止不受信任的脚本和内容加载

    Content-Security-Policy: default-src 'self';

  2. 最小化权限,确保应用程序在运行时具有最小权限。避免在js中使用特权模式,限制对敏感操作和数据访问。

存储型:

比如博客网站,文章写入scirpt脚本,存到后台服务器

下次别人访问该文章,后台返回script脚本,客户端会执行这个脚本。

如果脚本里有恶意链接,就可以将用户的cookie信息,给传到恶意服务器

  • 如何防范:

1.转义输出;前端对script标签,特殊字符串进行转义。防止浏览器执行用户输入的内容

2.验证和过滤:仅允许预期的,安全的字符和内容通过(前后端做)

3.使用安全的编程框架和库。angular dom,等等

DOM型

客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。(与上面两个的区别,恶意代码不发往服务器)

例如:url中带有参数,参数会直接渲染在页面上。(也可以是表单数据)

需要特别注意以下的用户输入源 document.URL、 location.hash、 location.search、 document.referrer 等,如果输入恶意代码,就会被执行。

  • 如何预防:

输入验证:对所有用户输入进行验证,确保它们符合预期的格式和类型。不要讲不可信数据插入到html中

其他防御手段:

httpOnly: 在 cookie 中设置 HttpOnly 属性后,js脚本将无法读取到 cookie 信息。

csrf(Cross-site request forgery) 跨站请求伪造

它是指攻击者利用了用户的身份信息,执行了用户非本意的操作

身份信息:

cookie信息

模拟攻击实现代码:

复制一个有cookie信息的请求,

新建index.html ,用img src 来发送该请求。

cookie信息会一并带过去

解决方法

  • cookie的SameSite

现在很多浏览器都支持禁止跨域附带的cookie,只需要把cookie设置的SameSite设置为Strict即可

SameSite有以下取值:

  • Strict:严格,所有跨站请求都不附带cookie,有时会导致用户体验不好
  • Lax:宽松,所有跨站的超链接、GET请求的表单、预加载连接时会发送cookie,其他情况不发送
  • None:无限制

这种方法非常简单,极其有效,但前提条件是:用户不能使用太旧的浏览器

  • 验证请求来源站点:referer和Origin

页面中的二次请求都会附带referer或Origin请求头,向服务器表示该请求来自于哪个源或页面,服务器可以通过这个头进行验证

Referer缺点:在以下两种情况下,Referer 不会被发送:

-来源页面采用的协议为表示本地文件的 "file" 或者 "data" URI;

-当前请求页面采用的是非安全协议,而来源页面采用的是安全协议(HTTPS)

  • 使用非cookie令牌

这种做法是要求每次请求需要在请求体或请求头中附带token

请求的时候:authorization: token

缺点:localstorage,兼容性差 。

  • 验证码

验证码被认为是对抗 CSRF 攻击最简洁而有效的防御方法。

这种做法是要求每个要防止CSRF的请求都必须要附带验证码

不好的地方是容易把正常的用户逼疯

  • 表单随机数

这种做法是服务端渲染时,生成一个随机数,客户端提交时要提交这个随机数,然后服务器端进行对比

该随机数是一次性的

流程:

  1. 客户端请求服务器,请求添加学生的页面,传递cookie

  2. 服务器

    1. 生成一个随机数,放到session中
    2. 生成页面时,表单中加入一个隐藏的表单域<input type="hidden" name="hash" value="<%=session['key'] %>">
  3. 填写好信息后,提交表单,会自动提交隐藏的随机数

  4. 服务器

    1. 先拿到cookie,判断是否登录过
    2. 对比提交过来的随机数和之前的随机数是否一致
    3. 清除掉session中的随机数
  • 二次验证

当做出敏感操作时,进行二次验证

参考:juejin.cn/post/694527…