十分钟内理解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

 

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

相关推荐

Linux stat命令示例(系统管理命令)

说明stat命令用于显示文件或文件系统的状态。包含了文件的详细信息。语法stat [OPTION]... FILE... 常用选项-L(或--dereference):显示符号链接-f(或--file-system):显示文件系统的状态信息,而不是文件的状态信息-t,(或--terse):简洁模式,只显示摘要信息示例显示文件信息$stat /dev/vda1  Fil

Linux uname命令的示例(系统管理命令)

说明打印系统相关信息,包括内核版本号、硬件架构、主机名称和操作系统类型等。语法uname [OPTION]... 常用选项-a,--all:显示全部的信息;-m,--machine:显示机器类型;-n,-nodename:显示在网络上的主机名称;-r,--release:显示操作系统的发行编号;-s,--sysname:显示操作系统名称;-v:显示操作系统的版本;-p,--process

Linux netstat命令示例(系统管理命令)

说明netstat命令主要是显示系统的网络信息,如网络连接,路由表,接口统计信息,masquerade连接和多播成员。基本使用直接执行netstat输出$netstat Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address

[译]5分钟内学习CSS变量

CSS自定义属性(也称为变量)对于前端开发人员来说是一个巨大的胜利。 它将变量的强大功能引入CSS,从而减少重复,代码更可读以及更灵活。另外,与CSS预处理器的变量不同,CSS变量实际上是DOM的一部分,它是有很多好处。 所以他们基本上像SASS和LESS的变量。 在这篇文章中,我会给你一个关于这种新技术如何工作的速成课程。我还创建了一个免费的关于CSS变量的课程,它

理解React Native的Props和State

Props和State是React Native分别用来控制组件中两种不同类型的数据。Propsprops是Properties的简写,称为属性。props的特点是在组件内它是不可变,或者说不能被修改。在React数据流是单向的,从父组件到子组件的方向传递。props就是组件从父组件接收的数据,在组件内部是不能对它修改。props不可变的特性是有助于我们写可复用的组件。我们只需要对一个组

[译]5分钟学习React.js

本教程将通过构建一个非常简单的应用程序,让你对React.js有基本的了解。我会抛弃所有我认为不是核心的东西。如果你喜欢我的教学风格,在我们即将推出免费的React.js课程时你想收到通知,可以在此留下电子邮件。设置在开始使用React时,你应该使用最简单的设置:在html文件中使用script标签导入React和ReactDOM库,如下所示:<html><head><

SwiftUI Alerts的使用示例

SwiftUI里的Alerts可以分为三类:警告对话框(Alert Dialogs)操作列表(Action Sheets)弹窗(Popovers)警告对话框(Alert Dialogs)示例使用SwiftUI,我们可以很容易地使用声明的方式来创建警告框以及定义操作,示例如下:struct AlertView: View { @State private var showingAlert =

JavaScript简单的Async/Await示例

Node 7.6 新增了async/await! 下面以一个简单可运行的示例来说明async /await的使用。const axios = require('axios'); //基于promise的http请求框架function getCoffee() { return new Promise(resolve => { setTimeout(() => resolve('

LINQ group by的使用示例

下面通过一个示例来展示linq中group by的使用。类Person如下:class Person { internal int PersonId; internal string car ; }Person列表List<Person>:persons[0] = new Person { PersonID = 1, car = "Ferrari" }; person