且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》——1.2 跨域资源共享

更新时间:2022-10-06 16:59:55

本节书摘来自华章计算机《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》一书中的第1章,第1.2节,作者:(美) 希马(Shema, M.)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.2 跨域资源共享

HTML5的一些特性反映了Web开发人员的真实经验,他们将浏览器的能力边界进行了拓展,目的是创建与本地应用程序在外观、感觉、操作方面没有区别的应用程序。被拓展的边界之一就是古老的同源策略(Same Origin Policy),同源策略是第一代浏览器中为数不多的安全机制之一。开发人员经常会有合法的理由希望能拓展同源策略,其目的可能是为了使得某个网站能更好地传递具体的域名,或者是让在不相关的域上的站点进行有用的交互。跨域资源共享(Cross-Origin Resource Sharing,CORS)允许站点开发人员可以对某个域授权,使它可以访问从另一个域加载的资源的内容(默认的浏览器行为允许请求不同域的资源,但是对每个响应的资源内容的访问是针对每个域隔离开来的。一个站点不能够窥探另一个站点的DOM,例如设置cookie、读取包含用户名的文本节点、注入JavaScript节点等)。
浏览器产生请求的通用工具之一就是XMLHttpRequest(XHR)对象,XHR对象是本书中会经常出现的内容。它的两个主要特性分别是能够产生异步后台请求和能够使用非GET(non-GET)方法,使得它成为了漏洞利用的关键组成部分。因此,浏览器逐渐限制了XHR的能力,目的是减少它暴露安全问题的不利影响。通过使用CORS,网站开发人员可以在不至于给浏览器带来过度风险的前提下放松上述限制。
跨域资源的安全边界是通过请求及响应的标头来建立的。浏览器有三种请求标头(我们将会在介绍完所有这些标头之后介绍preflight(预检)这一概念):
Origin:初始化请求的资源的协议、主机名、端口号(scheme/host/port)。服务器必须对这个域授权共享。与这个标头相关联的安全性建立在卓越的浏览器上。它的值应当是由浏览器正确设置的,不应当被HTML、JavaScript或插件修改。
Access-Control-Request-Method:用在preflight请求中,用于确定服务器是否支持XHR对象希望使用的方法。例如,对于某个Web应用程序,浏览器可能只需要依赖GET方法,但是对于一个REST-ful网站,则需要大量的方法。这样,网站可能会对浏览器执行“最小特权”的概念,仅允许那些确实必需的方法。
Access-Control-Request-Headers:用在preflight请求中,用于确定服务器是否允许XHR对象希望设置的其他标头。例如,不允许客户端JavaScript对Origin标头(或者将在1.3节中介绍的任何Sec-header)进行操纵。另一方面,XHR对象可能希望通过POST方法来上传文件,此时最合理的做法是设置一个Content-Type标头,尽管浏览器会限制这个标头中包含的内容。
服务器可以使用五种响应标头,它们指示浏览器对跨域请求的响应数据如何授予共享访问权限:
Access-Control-Allow-Credentials:可能为“true”或“false”。默认情况下,浏览器不会在域间提交cookie、HTTP认证字符串(例如Basic、Digest、NTLM)或客户端SSL证书。这一限定能够防止恶意内容试图将证书泄露给未经许可的域。将这个标头设置为true表示允许在域间共享此种证书类别的所有数据。
Access-Control-Allow-Headers:这是一个请求可能包含的标头。有些标头是不可改变的,例如Host和Origin。它可以应用到类似Content-Type或自定义X-header的标头上。
Access-Control-Allow-Methods:这是一个请求可以用来获取资源的方法。通常被限定为那些必不可少的方法,经常只包含GET。
Access-Control-Allow-Origin:用来指定服务器允许浏览器共享该服务器的响应数据的域。其内容可能是明确的域、(匹配任意域的通配符)、null(拒绝请求)。通配符()总是阻止跨域请求中包含的证书,不论之前提到的Access-Control-Allow-Credentials标头设置成什么值。
Access-Control-Expose-Headers:浏览器可以让客户端看到的标头列表。例如,JavaScript能够从XHR响应中读取暴露出来的标头。
Access-Control-Max-Age:对preflight请求的响应所缓存的时间,以秒为单位。时间越短,对浏览器的负担越重,因为它必须为新的preflight请求更新CORS许可。时间越长,因为会过度宽容preflight请求的控制,潜在的暴露风险也会增加。这需要网站开发人员来决策。值得参考的值是Web应用程序维持用户会话的时间(不需要重新认证),就像很多网站中常见的“记住我”按钮那样。因此典型的持续时间可以是几分钟、一天或两周,当然,这个持续时间要尽可能短一些。
跨域的资源共享必须得到网站的许可。除非响应中包含与CORS相关的标头,否则对一般的GET和POST请求的响应数据的访问权限总是限定在相同的域中。服务器可以对这些“一般”类型的请求使用Access-Control系列的标头进行响应。其他情况下,浏览器可以首先通过使用一个preflight请求来建立CORS策略,当使用XHR对象时,这种策略最为常用。
在下面的例子中,假定HTML是从http://web.site的域加载的。下面的JavaScript显示了一个XHR请求,这个请求是由对另一个域的PUT方法构成,这个域要求包含证书(xhr.open()函数的第三个参数的值为“true”)。
《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》——1.2 跨域资源共享

处理xhr.send()时,浏览器发起一个preflight请求,以确定服务器是否愿意将自己的http://friendly.app域中的资源同请求资源的源http://web.site共享。请求的具体格式类似如下代码:
《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》——1.2 跨域资源共享

如果friendly.app的服务器希望同http://web.site共享资源,那么它将会回应类似如下的内容:
《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》——1.2 跨域资源共享

这种标头的交换指示浏览器将来自http://friendly.app域的响应内容公开给来自http://web.site的资源。这样,XHR对象可以从friendly.app接收JSON数据,并且web.site能够读取、操纵和显示这些数据。
CORS是域间的约定,指示浏览器放松同源策略,否则会使得某个源的响应数据不能够被另一个源的客户端资源所使用。允许CORS会为Web应用程序带来安全隐患,因此,当故意放松同源策略的约束时,仍要牢记它的原则:
确保服务器端代码总是验证Origin标头和Host标头是否匹配,并且在使用CORS标头进行响应之前,要确保该Origin标头位于被允许的值的列表之内。遵循“failing secure”原则,即任何错误都应该返回空响应或是内容最少的响应。
记住CORS是在每个域的基础上建立共享,而不是在每个资源的基础上。如果只需要共享一个资源,可以考虑将资源转移到它自己的子域中,而不要将Web应用程序的其他资源也共享出去。例如,为API访问建立一个单独的域,而不是通过网站的主域中的目录来共享API。
当为“Access-Control-Allow-Origin”标头使用通配符(*)时要小心。这个值将会把资源的数据(例如Web页面)公开给任意网站的页面。记住,同源策略并不阻止页面从无关的域中加载资源,它只是阻止页面读取来自那些域的响应数据。
评估HTML注入攻击(跨站脚本攻击)的附加影响。如果HTML注入攻击已经能够在被攻击者的域中成功执行,那么任何通过CORS建立的信任关系将会暴露给该漏洞利用。
CORS在HTML5中会被当作Web漏洞利用实用工具的特性之一。这并不意味着CORS有缺陷或不安全,而是意味着黑客将不断利用新的技术持续地从浏览器中窃取数据,扫描网络主机或开放端口,并注入JavaScript。Web应用程序不会因此变得更不安全,只不过漏洞利用会变得更加复杂。