CSRF的跨域问题详解
slug
series-status
status
summary
date
series
type
password
icon
tags
category
前言
近期在我面试各大厂商的过程中,发现今年大家格外喜欢问到这个CSRF和XSS的跨域问题,这里就临时增加一篇相关的文章来简单介绍一下这个问题,希望可以达到面试官的要求~
基础知识
CORS
简介
CORS(跨来源资源共享,Cross-Origin Resource Sharing)是一种用于控制浏览器如何处理跨域请求的安全机制。当一个网页的资源(如脚本、图片或样式)需要从一个不同的域名、协议或端口请求时,CORS就发挥作用。
在CORS之前,同源策略(Same-Origin Policy)是浏览器安全的核心原则,它规定一个网页只能请求与自身同源的资源。同源策略的目的是防止恶意网站利用跨域请求来窃取敏感数据。然而,随着Web应用变得越来越复杂,同源策略限制了合法的跨域资源共享。
CORS通过添加一组特定的HTTP响应头来解决这个问题,从而允许服务器指定哪些域名可以访问它的资源。浏览器在发起跨域请求时,会自动添加一个Origin头,表示请求的来源。服务器收到请求后,根据CORS策略决定是否允许请求,并在响应头中包含相应的CORS头信息。浏览器会根据这些响应头来决定是否允许请求。
主要的CORS响应头有:
- Access-Control-Allow-Origin:指定允许访问资源的源。它可以设置为特定的域名、*(表示允许任意域名)或者null(表示不允许任何域名)。
- Access-Control-Allow-Credentials:表示是否允许发送Cookie。默认情况下,CORS请求不会发送Cookie。如果服务器允许发送Cookie,这个响应头应设置为true。
- Access-Control-Allow-Methods:指定允许的HTTP方法,例如GET、POST、PUT、DELETE等。
- Access-Control-Allow-Headers:指定允许的HTTP请求头。这些请求头可以包括自定义头,如X-Requested-With、Content-Type等。
- Access-Control-Expose-Headers:指定哪些响应头可以被浏览器访问。默认情况下,浏览器只能访问6个基本响应头,包括Cache-Control、Content-Language、Content-Type、Expires、Last-Modified和Pragma。
- Access-Control-Max-Age:表示预检请求(Preflight request)的结果可以被缓存多长时间。预检请求是浏览器在实际发起跨域请求之前自动发送的一种OPTIONS请求,用于获取服务器的CORS策略。
通过正确配置CORS策略,Web开发人员可以在保证安全的同时允许合法的跨域资源共享。
CORS在后端是如何处理的
CORS的配置主要是由后端(服务器端)解决的。虽然浏览器负责处理跨域请求,但CORS策略实际上是在服务器端设置的。服务器通过在响应头中添加特定的CORS头信息来告诉浏览器哪些跨域请求是允许的。
后端开发人员需要根据具体的应用需求来设置CORS策略,例如允许哪些域名、哪些HTTP方法以及是否允许发送Cookie等。这些配置通常在服务器或API网关的代码中进行,或者在云服务提供商的管理控制台中设置。
例如,以下是一个简单的Express.js(Node.js框架)中的CORS配置示例:
在这个例子中,服务器允许来自"https://example.com"的跨域请求,并限制了允许的HTTP方法和请求头。同时,服务器也允许发送Cookie。
总之,CORS的配置主要是由后端解决的,前端只需确保正确处理服务器返回的CORS响应头即可。
同源策略(SOP)
概念
同源策略(Same-Origin Policy)是一种重要的浏览器安全机制,旨在保护用户隐私和数据安全。同源策略规定,一个Web页面只能访问与其自身同源的资源。这种限制可以防止恶意网站通过跨站请求窃取或操纵用户的敏感数据。
同源的定义基于以下三个要素:
- 协议:例如 HTTP 或 HTTPS。
- 域名:例如 example.com 或 example.org。
- 端口号:例如 80(HTTP的默认端口)或 443(HTTPS的默认端口)。
如果两个资源的这三个要素都相同,则它们被认为是同源的。否则,它们被认为是不同源的。
举个例子,以下URL是同源的:
而以下URL是不同源的:
- [http://example.com(端口80)](http://example.㯘(80)-po3l6510a/) 和 [https://example.com(端口443)](https://example.㯘(443)-m30nx732a/)
同源策略主要应用于以下场景:
- DOM访问:一个Web页面的脚本不能访问另一个不同源页面的DOM元素。
- Cookie:一个Web页面的脚本只能访问与其同源的Cookie,不能访问其他来源的Cookie。
- AJAX请求:浏览器通常不允许一个Web页面发起对不同源资源的AJAX请求。
虽然同源策略对Web安全至关重要,但它在某些情况下限制了合法的跨站资源共享。为了解决这个问题,跨来源资源共享(CORS,Cross-Origin Resource Sharing)应运而生。CORS是一种安全机制,允许服务器通过特定的HTTP响应头来指定哪些来源是可信的,从而允许合法的跨站资源共享。
总之,同源策略是浏览器用于保护用户隐私和数据安全的关键安全机制。它规定一个Web页面只能访问与其自身同源的资源。虽然同源策略有时会限制合法的资源共享,但可以通过CORS等技术实现安全的跨站资源共享。
跨域
概念
跨域(Cross-Domain)是Web开发中的一个重要概念,它指的是从一个域名请求另一个域名的资源。由于浏览器的同源策略限制,跨域请求通常会被阻止,以保护用户的隐私和数据安全。然而,在某些场景下,跨域资源共享是合法且必要的,因此需要采用特定的方法来实现安全的跨域请求。
- 跨域场景:
跨域请求涉及到不同的资源类型,如:
- AJAX请求(例如,从一个域名请求另一个域名的API)
- 图片、视频和音频资源
- CSS样式表
- 字体资源
- 脚本(例如,从CDN加载的JS库)
以下是一些不同源的示例:
- http://example.com 和 [http://example.org(不同的域名)](http://example.ᾗ()-ri1h917aia519fo33f/)
- http://example.com 和 [http://www.example.com(不同的子域名)](http://www.example.㯘()-ri1h917aia519fy1ix61f/)
- http://example.com:80 和 [http://example.com:8080(不同的端口号)](http://example.com:8080(不同的端口号)/)
- http://example.com 和 [https://example.com(不同的协议)](https://example.㯘()-ri1h672agpbb76obi1b/)
- 跨域常见解决方案:
为了实现安全的跨域请求,可以采用以下方法:
- CORS(跨来源资源共享):CORS是一种W3C推荐的跨域解决方案,它允许服务器通过设置特定的HTTP响应头来指定哪些来源是可信的。CORS允许服务器控制允许访问资源的域名、HTTP方法、请求头等。通过正确配置CORS策略,可以实现安全的跨域资源共享。
- JSONP(JSON with Padding):JSONP是一种早期的跨域解决方案,它利用了
<script>
标签的src属性不受同源策略限制的特性。JSONP通过动态创建<script>
标签并设置src属性为目标服务器的URL来发起跨域请求。服务器响应的数据会作为一个回调函数的参数返回。需要注意的是,JSONP只支持GET请求,且存在安全风险,因此现在已经逐渐被CORS所取代。
- 服务器代理:通过在同源服务器上设置代理服务,将跨域请求转发到目标服务器。这样,浏览器就可以访问同源服务器上的代理服务,而代理服务会负责与目标服务器进行通信。这种方法可以绕过同源策略的限制,但可能会增加服务器的负担和复杂性。
- WebSocket:WebSocket是一种双向通信协议,它在单个TCP连接上提供全双工通信。WebSocket不受同源策略的限制,因此可以用于实现跨域通信。
同源策略和跨域有什么关系
跨域和同源策略是Web开发中密切相关的两个概念,它们共同维护了Web安全和数据隐私。理解它们之间的关系和联系有助于更好地设计和开发Web应用程序。
同源策略(Same-Origin Policy)是一种浏览器安全机制,旨在保护用户的隐私和数据安全。它规定一个Web页面只能访问与其自身同源的资源。同源的定义基于以下三个要素:协议(如HTTP或HTTPS)、域名(如example.com)和端口号(如80或443)。同源策略限制了Web页面在以下几个方面的访问能力:
- 访问其他页面的DOM元素
- 读取其他来源的Cookie
- 发起对其他来源资源的AJAX请求
跨域(Cross-Domain)指的是从一个域名请求另一个域名的资源。由于同源策略的限制,浏览器默认会阻止跨域请求。但在实际开发中,跨域请求很常见,尤其是当一个Web应用需要访问其他域名的API或资源时。为了实现安全的跨域资源共享,需要采用一些方法来解决同源策略带来的限制,例如CORS(跨来源资源共享)。
总结一下跨域和同源策略之间的关系和联系:
- 同源策略是浏览器的一种安全机制,用于限制Web页面访问其他来源的资源。它可以保护用户的隐私和数据安全。
- 跨域是指从一个域名请求另一个域名的资源。由于同源策略的限制,跨域请求默认会被浏览器阻止。
- 跨域和同源策略之间的联系在于,跨域是为了解决同源策略带来的限制,实现安全的跨站资源共享。跨域方案(如CORS)允许服务器指定哪些来源是可信的,从而放宽同源策略的限制。
- 同源策略和跨域解决方案共同维护了Web安全,使得Web应用可以在保护用户隐私和数据安全的同时实现跨站资源共享。
利用JSONP跨域
基本流程
JSONP(JSON with Padding)是一种实现跨域数据请求的方法,它利用了浏览器允许跨域加载 script 标签的特性。JSONP 通过在客户端创建一个动态的 script 标签,并将请求的 URL 设置为 script 标签的 src 属性,从而实现跨域数据请求。服务端返回的数据会被封装成一个 JavaScript 函数调用,客户端通过提前定义好的回调函数来处理返回的数据。
以下是利用 JSONP 实现跨域的步骤:
- 客户端定义回调函数:在客户端,你需要定义一个用于处理返回数据的回调函数。例如:
- 客户端创建动态 script 标签:客户端需要创建一个动态的 script 标签,并将请求的 URL 设置为 script 标签的 src 属性。URL 中应包含回调函数的名称。例如:
- 服务器端处理请求:在服务器端,你需要检查请求中的
callback
参数,并将返回的 JSON 数据封装成一个 JavaScript 函数调用。例如,服务器端可以返回以下数据:
- 客户端处理返回的数据:当浏览器加载完动态创建的 script 标签后,会自动执行服务器返回的 JavaScript 函数调用。此时,客户端中定义的
handleData
函数将被调用,并接收到服务器返回的数据。
需要注意的是,JSONP 存在一定的安全风险,因为它允许跨域加载并执行任意的 JavaScript 代码。因此,在使用 JSONP 时,务必确保信任数据提供方。另外,现代 Web 开发中,CORS 已经成为更加推荐的跨域解决方案,因为它提供了更好的安全性和更灵活的控制。
JSONP的安全风险
JSONP 存在一定的安全风险,主要有以下两点:
- 跨站脚本攻击(XSS):JSONP 需要动态加载 script 标签,而 script 标签允许跨域加载并执行任意 JavaScript 代码。这为跨站脚本攻击(XSS)提供了可能。如果 JSONP 请求的 URL 指向了一个恶意网站,恶意网站可以返回恶意 JavaScript 代码,并在用户的浏览器上执行。
例如,一个攻击者可能会将 JSONP 请求的 URL 修改为恶意网站的 URL:
恶意网站可能返回如下恶意代码:
此时,恶意代码将在用户浏览器中执行,可能导致用户数据泄露、篡改页面内容等问题。
- 数据劫持:JSONP 允许跨域请求数据,但它没有对数据的来源进行严格限制。因此,如果攻击者可以劫持或篡改 JSONP 请求的数据,他们可以在用户的浏览器中注入恶意数据。
例如,假设你正在使用 JSONP 从一个不安全的 API 获取数据:
攻击者可能劫持 API 请求,并返回如下恶意数据:
这种情况下,当你在页面上显示返回的数据时,恶意代码会被执行,可能导致安全问题。
要避免 JSONP 的安全风险,你可以采取以下措施:
- 只信任可靠的数据源:确保 JSONP 请求的 URL 指向可信任的服务器。
- 对返回的数据进行过滤和验证:在处理 JSONP 返回的数据之前,对数据进行过滤和验证,以防止恶意代码的执行。
- 考虑使用 CORS:CORS 提供了更好的安全性和更灵活的控制,是现代 Web 开发中推荐的跨域解决方案。
利用CORS跨域
基本流程
CORS(跨来源资源共享,Cross-Origin Resource Sharing)是一种用于克服浏览器同源策略限制的机制。通过在服务器端配置CORS策略,可以允许浏览器执行安全的跨域请求。
要利用CORS实现跨域,需要遵循以下步骤:
- 服务器端设置: 在服务器端,需要设置特定的HTTP响应头,以允许跨域访问。以下是一些常用的CORS相关响应头:
Access-Control-Allow-Origin
:指定允许访问资源的来源。可以设置为特定的域名(如http://example.com
)或通配符(允许任何来源访问)。
Access-Control-Allow-Methods
:指定允许的HTTP请求方法,如GET
、POST
、PUT
、DELETE
等。
Access-Control-Allow-Headers
:指定允许的请求头,如Content-Type
、Authorization
等。
Access-Control-Allow-Credentials
:指定是否允许浏览器携带凭据(如Cookie)进行跨域请求。如果设置为true
,则Access-Control-Allow-Origin
不能设置为通配符,必须指定具体的域名。
Access-Control-Max-Age
:指定预检请求(Preflight Request)的结果缓存时间,以减少预检请求的次数。
以下是一个典型的CORS配置示例(以Node.js Express框架为例):
- 前端请求: 在前端,可以像正常发起AJAX请求一样发起跨域请求。如果服务器端已正确配置CORS策略,浏览器会自动处理CORS响应头,并允许跨域请求。以下是一个典型的跨域请求示例(使用Fetch API):
总之,要利用CORS实现跨域,首先需要在服务器端配置CORS策略,设置允许访问的来源、请求方法、请求头等。然后,在前端发起跨域请求时,无需特殊处理,只需正常发起AJAX请求。如果服务器端已正确配置CORS策略,浏览器会自动处理CORS响应头,并允许跨域请求。
以下是一些常见的前端请求库和方法,可用于发起跨域请求:
- XMLHttpRequest:这是早期的AJAX请求库,可以用于发起跨域请求。但需要注意的是,XMLHttpRequest在某些浏览器中可能存在兼容性问题。
- Axios:Axios 是一个流行的前端 HTTP 请求库,支持 Promise 和基于 XMLHttpRequest 的跨平台请求。要使用 Axios,首先需要安装该库(如通过 npm 或 yarn)。
- jQuery:jQuery 是一个流行的 JavaScript 库,其中包含一个 AJAX 请求功能。如果你的项目已经使用了 jQuery,可以利用 jQuery 发起跨域请求。
使用这些库和方法发起跨域请求时,只需确保服务器端已正确配置 CORS 策略,浏览器将自动处理 CORS 响应头并允许跨域请求。
CSRF中的跨域问题
为什么CORS不能完全阻止CSRF中的跨域问题
实际上,CORS 并不直接处理 Cookie。CORS 的主要功能是控制跨域请求中哪些 HTTP 头和方法是允许的。携带 Cookie 的行为是由浏览器的同源策略控制的,与 CORS 无关。但是,CORS 可以通过设置
Access-Control-Allow-Credentials
头来控制是否允许在跨域请求中携带 Cookie。通常情况下,跨域请求是不会自动携带 Cookie 的。但是,当你明确设置请求的
withCredentials
为 true
时,浏览器会在跨域请求中携带 Cookie。此时,服务器端需要在响应头中添加 Access-Control-Allow-Credentials: true
,以告诉浏览器允许这种跨域请求携带 Cookie。如果服务器没有设置这个响应头,那么浏览器将拒绝这个跨域请求。然而,对于 CSRF 攻击,攻击者通常会使用简单的 HTML 表单或者使用
img
标签等方式发起一个跨站请求。这种情况下,浏览器会自动将目标网站的 Cookie 附加到请求中,而不需要设置 withCredentials
。因此,CORS 机制无法阻止这种攻击。例如,攻击者在恶意网站上创建一个表单:
当用户点击“Click me”按钮时,浏览器会向目标网站发送一个 POST 请求,携带用户的 Cookie。尽管目标网站可能已经正确配置了 CORS,但是它无法防止这种 CSRF 攻击。
为了防止 CSRF 攻击,需要采取其他安全措施,如使用 CSRF 令牌、设置 SameSite Cookie 属性等。
为什么同源策略不能阻止CSRF攻击
同源策略(Same-Origin Policy)是浏览器的一种安全策略,它限制了来自不同源的文档或脚本之间的交互。同源策略在很大程度上能够提高 Web 安全,但它本身无法完全避免 CSRF 攻击。
同源策略主要限制以下几种行为:
- 限制跨域读取数据:例如,一个来自源 A 的脚本无法读取源 B 的数据,除非源 B 显式允许(如通过 CORS)。
- 限制跨域写入数据:例如,一个来自源 A 的脚本可以在源 B 上执行某些操作,但是它无法读取到操作的结果。
- 限制跨域嵌套:例如,一个来自源 A 的页面无法在 iframe 中嵌套源 B 的页面,除非源 B 显式允许。
尽管同源策略限制了跨域交互,但它并不能完全阻止 CSRF 攻击。CSRF 攻击利用的是用户的浏览器自动发送 Cookie 的特性。当用户访问恶意网站时,该网站发起的请求会携带用户在目标网站上的 Cookie。由于这个请求是从用户的浏览器发出的,同源策略并不能阻止这种行为。
补充
CSRF(Cross-site request forgery)跨站请求伪造,是一种常见的攻击方式。是指 A 网站正常登陆后,cookie 正常保存,其他网站 B 通过某种方式调用 A 网站接口进行操作,A 的接口在请求时会自动带上 cookie。
上面说了,SOP 可以通过 html tag 加载资源,而且 SOP 不阻止接口请求而是拦截请求结果,CSRF 恰恰占了这两个便宜。
所以 SOP 不能作为防范 CSRF 的方法。
对于 GET 请求,直接放到
<img>
就能神不知鬼不觉地请求跨域接口。对于 POST 请求,很多例子都使用 form 提交:
归根到底,这两个方法不报跨域是因为请求由 html 控制,你无法用 js 直接操作获得的结果。
SOP 与 ajax
对于 ajax 请求,在获得数据之后你能肆意进行 js 操作。这时候虽然同源策略会阻止响应,但依然会发出请求。因为执行响应拦截的是浏览器而不是后端程序。事实上你的请求已经发到服务器并返回了结果,但是迫于安全策略,浏览器不允许你继续进行 js 操作,所以报出你熟悉的 blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.。
所以再强调一次,同源策略不能作为防范 CSRF 的方法。
为什么同源策略不能阻止XSS攻击获取cookie
同源策略(Same-Origin Policy)是一种浏览器安全策略,它限制了来自不同源的文档或脚本之间的交互。然而,同源策略无法阻止 XSS 攻击获取 Cookie 等敏感信息,原因如下:
XSS 攻击指的是攻击者向目标网站注入恶意脚本,当其他用户访问目标网站时,恶意脚本会在用户的浏览器中执行。当 XSS 攻击发生时,恶意脚本实际上是在受害者的浏览器中运行,与目标网站的源相同。换句话说,恶意脚本是在目标网站的上下文中执行的,因此同源策略不会对其产生限制。
由于恶意脚本是在同源环境下执行的,它可以访问目标网站的所有资源,包括 Cookie。攻击者可以利用这一点,通过恶意脚本窃取用户的 Cookie 信息,进而实施其他攻击,如会话劫持。
XSS中的跨域问题
在某些场景下,XSS 攻击可能涉及到跨域问题。以下是一些可能涉及跨域操作的 XSS 攻击场景:
- 数据窃取:攻击者可能利用 XSS 攻击将受害者的敏感数据(如 Cookie、访问令牌等)发送到攻击者控制的服务器。在这种情况下,攻击者的服务器与目标网站是不同源的,因此涉及跨域请求。例如,攻击者可以在恶意脚本中创建一个新的 HTTP 请求,将窃取的数据发送到攻击者的服务器:
- 外部脚本加载:攻击者可能利用 XSS 攻击在受害者的浏览器中加载来自不同源的恶意脚本。这种情况下,虽然恶意脚本本身可能涉及跨域加载,但这并不违反同源策略,因为浏览器允许跨域加载脚本资源。例如,攻击者可以通过以下方式在受害者的浏览器中加载一个外部恶意脚本:
- 第三方库或插件的漏洞:如果目标网站使用了包含漏洞的第三方库或插件,攻击者可能会利用这些漏洞进行跨域操作。例如,某些 JSONP 实现可能存在安全漏洞,允许攻击者劫持 JSONP 响应并注入恶意脚本。这种情况下,攻击者可以利用跨域请求来执行恶意脚本。
虽然这些场景中的 XSS 攻击可能涉及跨域操作,但这并不意味着同源策略无效。同源策略仍然起到了限制不同源之间资源访问的作用。
Loading...