十分钟内理解CORS, XSS和CSRF的示例

本文应该是现有Web安全标准,最常见的Web攻击及其预防方法的切入点。 最后,你还将明白Samy是如何以及为什么成为每个人的英雄(我想除了Rupert Murdoch外)。

跨域资源共享:CORS

跨域资源共享或CORS(Cross-origin resource sharing)是 IE10+、Chrome 4+、Firefox 3.5+ 或 2012 年之后发布的几乎所有浏览器版本(Opera Mini 除外)的安全特性

当域名website.com所在的服务器上配置了CORS,那么从此域名通过AJAX请求的资源也必须是在同一域名下。

换句话说,如果我们在 domain-b.com 上启用CORS并将其配置为仅允许来自域 domain-b.com 的 GET 请求,那么在域名domain-a.com的页面上,使用的图片https://domain-b.com/images/example.png,对于大多数访客(这里主要说的是使用了支持CORS特性的浏览器),在domain-a.com页面画布上将加载不了图片。

对于任何不遵守 CORS 政策的工具或浏览器请求时,受CORS保护的资源仍然可用。

CORS配置

CORS默认是禁用的,这意思是指服务器端没有配置CORS的处理程序,意味着你无法通过XHR来访问非同源的资源。 基本上,如果你不做任何操作或为特定域专门启用CORS,那么任何试图访问你资源的AJAX请求都会被拒绝,因为 Web浏览器遵从CORS策略。

这就是开始使用VueJS和 NodeJS 开发SPA(单页面应用时遇到CORS问题的原因。 VueJS应用程序在 http://localhost:8080上,当尝试在http://localhost:8000上访问NodeJS服务器应用时,会报错“No Access-Control-Allow-Origin header is present”,因为这两个域名是不同源(ORIGIN,由PROTOCOL、HOST 和 PORT组合确定源)。

VueJS在开发模式下,CORS问题的修复是在vue.config.js 文件中设置 devServer 代理,如下所示:

module.exports = {
  ...
  devServer: {
    proxy: 'http://localhost:8000',
  },
  ...
}

在生产中配置CORS,需要为OPTIONS请求添加适当监听器。监听器拦截请求后,发送状态码为200的响应,请求体为空,并且附上想要的CORS 策略的Header:

Access-Control-Allow-Origin: https://domain-b.com
Access-Control-Allow-Methods: GET

有关如何配置 CORS 的更多信息,请查看 https://enable-cors.org/index.html ,并深入了解 CORS 政策检查 https://livebook.manning.com/book/cors-in-action/part-1/

跨站点脚本:XSS

跨站点脚本XSS(Cross Site Scripting),是一种注入类型的攻击。 它被 OWASP 列为 2017 年发现的前10 个漏洞中的第 7 个。跨站点脚本是攻击者将恶意脚本注入受信任网站的方法。(部分更新,感谢 Sandor)此类攻击有 3 种类型。

  1. 存储的XSS - 来自未受保护和未清理的用户输入的漏洞,这些用户输入直接存储在数据库中并显示给其他用户。
  2. 反射型XSS - 来自直接在网页中使用的URL中未受保护和未净化的值的漏洞。
  3. 基于DOM的XSS - 与反射XSS类似,不同之处在于基于DOM的XSS甚至不会进入服务器端。

攻击

1. 存储的XSS

这是一个攻击的例子。 攻击者进入你的网站并找到未受保护的输入字段,例如评论字段或用户名字段,并输入恶意脚本而不是预期值。 之后,只要该值应该显示给其他用户,它就会执行恶意代码。 恶意脚本可能会尝试访问你在其他网站上的帐户,可能参与DDoS攻击或类似攻击。 

示例图(来源 geeksforgeeks.org):

2. 反射型XSS

反射型 XSS 是攻击者发现具有此类漏洞的页面上进行的攻击,例如:

  • 预期网址:https://mywebpage.com/search?q=javascript
  • 恶意网址:https://mywebpage.com/search?q=<script>alert('幸运的是,这不起作用!')</script>
<body>
...
<div> showing results for keyword 
<script> document.write(window.location.href.substr(window.location.href.indexOf('q=') + 2))
</script>
</div>
...
...JavaScript results...
...
</body>

发现后,攻击者诱使用户点击此类恶意 URL。用户敏感数据被利用。

geekforgeeks.com 提供的示例说明了攻击的生命周期:

3. 基于DOM的XSS

这种攻击与反射相同,但不同的是,恶意URL部分根本不会发送到服务器。对于上面的例子:

  • 预期网址:https://mywebpage.com/search?q=javascript
  • 恶意URL(反射型 XSS):https://mywebpage.com/search?q=<script>alert('幸运的是,这不起作用!')</script>
  • 恶意URL(基于 DOM 的 XSS):https://mywebpage.com/search#q=<script>alert('幸运的是,这不起作用!')</script>

不同之处在于使用字符# 而不是?。浏览器不会将#之后的部分URL发送到服务器,因此它们直接将其传递给客户端代码。

保护

用户输入在应用程序中使用的每个值(包括服务器端和客户端)都应视为不受信任的数据,因此应在使用前进行处理! 还应该在服务器应用程序和客户端应用程序中进行安全检查!

此文档中所示,VueJS在从变量中获取值之前会自行转义字符串。较新版本的 Angular也隐式转义字符串,而如果使用Vanilla JS、JQuery 或类似的,应该手动实现字符串转义。

下面列出了三种最常见的处理不受信任数据的方法,理想的方法取决于需要处理的字段的实际类型。

1.字符串验证

验证是用户定义一组规则并要求不受信任的数据在继续之前满足这些规则的方法。这种方法适用于数值、用户名、电子邮件、密码和具有具体语法规则的类似字段。

2.字符串转义

escape方法对允许用户使用标点符号的情况很有用。 此方法遍历字符串并查找特殊字符,例如 < > 并将它们替换为适当的 HTML 字符实体名称。 基本使用如下:

function escapeText(text) {
  return text.replace(/&/g, '&amp;')
             .replace(/</g, '&lt;')
             .replace(/>/g, '&gt;')
             .replace(/"/g, '&quot;')
}

同样,先检查现有的library,再继续编写自己的。

3. 字符串清理

当允许用户在他们的评论、文章或类似内容中输入一些 HTML 标记时,使用净化字符串。 sanitize方法遍历文本并查找您指定的 HTML标记并将其删除。 使用这种方法的最受欢迎的库之一是 Google Closure

这种方法资源昂贵并且被认为是有害的,所以在选择它之前做更多的研究。

Web 浏览器(从哪个版本开始没有可用的资源,IE 在 2014 年修复了这个问题。)在将 URL 发送到服务器端并使其在 window.location 对象中可用之前自动转义 URL,因此第 2 和第 3 类型的攻击只是在这里 了解它们并明确 URL 参数也应被视为不受信任的数据。

或有关 XSS 的更多详细信息以及如何在处理大量不受信任的数据时正确保护您的应用程序,请查看 OWASP关于 XSS 预防的手册清单

跨站点请求伪造:CSRF

跨站点请求伪造CSRF(Cross site request forgery)是一种攻击类型,当恶意网站、电子邮件、博客、即时消息或程序导致用户的 Web 浏览器在用户经过身份验证的其他受信任站点上执行不需要的操作时,就会发生这种攻击。 当浏览器自动发送授权资源(例如会话 cookie、IP 地址或类似请求)时,可能会出现此漏洞。

攻击

假设用户登录到你未受保护的证券交易所Web应用程序,并且你正在使用会话cookie或JWT cookie进行身份验证。 攻击者还使用你的服务,并能够检查您的 API 是如何工作的。 攻击者诱骗用户执行脚本(通过单击电子邮件或类似邮件中的垃圾邮件链接),该脚本将向API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS(糟糕的 API 设计,不要)发送请求 任务)。 由于请求是从浏览器执行的,每次请求都会发送身份验证数据,因此你的证券交易所 Web 服务器将成功验证用户并执行交易,而被欺骗的用户将失去所有余额,甚至都不知道,因为一切都发生在后台。 示意图(来源 miro.medium.com):

保护

幸运的是,有一些易于实现的模式可以防止这种 Web 攻击。最常见的模式之一是使用 CSRF 令牌。基本流程如下:

  1. 为每个用户的请求生成唯一的令牌,即所谓的 CSRF 令牌。
  2. 将其安全地存储在服务器上并将其作为响应的有效负载发送回用户。
  3. 将 CSRF 令牌存储在客户端。
  4. 当用户尝试执行任何状态改变的请求时,发送带有请求的 CSRF 令牌作为有效负载。
  5. 在服务器端执行该请求之前,请检查 CSRF 令牌是否存在且有效。

这是防止所有用户遭受 CSRF 攻击的最简单方法。

如果你只与使用现代浏览器的访问者打交道,那么您可以依赖会话 cookie 的 SameSite 属性。(感谢 Gergely)

由于服务器的响应在 XHR 响应中是可处理的,因此如果您的 Web 应用程序易受 XSS 攻击,则无法防止 CSRF 攻击!

要深入了解,请阅读OWASP cheatsheet on CSRF

额外信息

关于 Samy 的短纪录片,蠕虫的作者早在 2005 年就利用 XSS 漏洞摧毁了 MySpace,通过了 MySpace 的 CSRF 防御。
https://youtu.be/DtnuaHl378M

有关萨米蠕虫的更多信息
https://samy.pl/myspace/tech.html

 

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0