者 | 浪里行舟
责编 | 胡巍巍
在互联网时代,数据安全与个人隐私受到了前所未有的挑战,各种新奇的攻击技术层出不穷。如何才能更好地保护我们的数据?本文主要侧重于分析几种常见的攻击的类型以及防御的方法。
XSS
XSS (Cross-Site Scripting),跨站脚本攻击,因为缩写和 CSS重叠,所以只能叫 XSS。跨站脚本攻击是指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或JavaScript进行的一种攻击。
跨站脚本攻击有可能造成以下影响:
XSS 的原理是恶意攻击者往 Web 页面里插入恶意可执行网页脚本代码,当用户浏览该页之时,嵌入其中 Web 里面的脚本代码会被执行,从而可以达到攻击者盗取用户信息或其他侵犯用户安全隐私的目的。
XSS 的攻击方式千变万化,但还是可以大致细分为几种类型。
1.非持久型 XSS(反射型 XSS )
非持久型 XSS 漏洞,一般是通过给别人发送带有恶意脚本代码参数的 URL,当 URL 地址被打开时,特有的恶意代码参数被 HTML 解析、执行。
举一个例子,比如页面中包含有以下代码:
1<select> 2 <script> 3 document.write('' 4 + '<option value=1>' 5 + location.href.substring(location.href.indexOf('default=') + 8) 6 + '</option>' 7 ); 8 document.write('<option value=2>English</option>'); 9 </script> 10</select>
攻击者可直接通过URL (类似:https://xxx.com/xxx?default=<script>alert(document.cookie)</script>) 注入可执行的脚本代码。不过一些浏览器如Chrome其内置了一些XSS过滤器,可以防止大部分反射型XSS攻击。
非持久型 XSS 漏洞攻击有以下几点特征:
为了防止出现非持久型 XSS 漏洞,需要确保这么几件事情:
2.持久型 XSS(存储型 XSS)
持久型 XSS 漏洞,一般存在于 Form 表单提交等交互功能,如文章留言,提交文本信息等,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。
举个例子,对于评论功能来说,就得防范持久型 XSS 攻击,因为我可以在评论中输入以下内容
主要注入页面方式和非持久型 XSS 漏洞类似,只不过持久型的不是来源于 URL,referer,forms 等,而是来源于后端从数据库中读出来的数据 。持久型 XSS 攻击不需要诱骗点击,黑客只需要在提交表单的地方完成注入即可,但是这种 XSS 攻击的成本相对还是很高。
攻击成功需要同时满足以下几个条件:
持久型 XSS 有以下几个特点:
3.如何防御
对于 XSS 攻击来说,通常有两种方式可以用来防御。
1) CSP
CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。
通常可以通过两种方式来开启 CSP:
这里以设置 HTTP Header 来举例:
1Content-Security-Policy: default-src 'self'
1Content-Security-Policy: img-src https://*
1Content-Security-Policy: child-src 'none'
如需了解更多属性,请查看Content-Security-Policy文档
对于这种方式来说,只要开发者配置了正确的规则,那么即使网站存在漏洞,攻击者也不能执行它的攻击代码,并且 CSP 的兼容性也不错。
2) 转义字符
用户的输入永远不可信任的,最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义
1function escape(str) { 2 str = str.replace(/&/g, '&') 3 str = str.replace(/</g, '<') 4 str = str.replace(/>/g, '>') 5 str = str.replace(/"/g, '&quto;') 6 str = str.replace(/'/g, ''') 7 str = str.replace(/`/g, '`') 8 str = str.replace(/\//g, '/') 9 return str 10}
但是对于显示富文本来说,显然不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。对于这种情况,通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。
1const xss = require('xss') 2let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>') 3// -> <h1>XSS Demo</h1><script>alert("xss");</script> 4console.log(html)
以上示例使用了 js-xss 来实现,可以看到在输出中保留了 h1 标签且过滤了 script 标签。
3) HttpOnly Cookie。
这是预防XSS攻击窃取用户cookie最有效的防御手段。Web应用程序在设置cookie时,将其属性设为HttpOnly,就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。
CSRF
CSRF(Cross Site Request Forgery),即跨站请求伪造,是一种常见的Web攻击,它利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作。
1.CSRF攻击的原理
下面先介绍一下CSRF攻击的原理:
完成 CSRF 攻击必须要有三个条件:
我们来看一个例子: 当我们登入转账页面后,突然眼前一亮惊现"XXX隐私照片,不看后悔一辈子"的链接,耐不住内心躁动,立马点击了该危险的网站(页面代码如下图所示),但当这页面一加载,便会执行submitForm这个方法来提交转账请求,从而将10块转给黑客。
2.如何防御
防范 CSRF 攻击可以遵循以下几种规则:
1) SameSite
可以对 Cookie 设置 SameSite 属性。该属性表示 Cookie 不随着跨域请求发送,可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
2) Referer Check
HTTP Referer是header的一部分,当浏览器向web服务器发送请求时,一般会带上Referer信息告诉服务器是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。可以通过检查请求的来源来防御CSRF攻击。正常请求的referer具有一定规律,如在提交表单的referer必定是在该页面发起的请求。所以通过检查http包头referer的值是不是这个页面,来判断是不是CSRF攻击。
但在某些情况下如从https跳转到http,浏览器处于安全考虑,不会发送referer,服务器就无法进行check了。若与该网站同域的其他网站有XSS漏洞,那么攻击者可以在其他网站注入恶意脚本,受害者进入了此类同域的网址,也会遭受攻击。出于以上原因,无法完全依赖Referer Check作为防御CSRF的主要手段。但是可以通过Referer Check来监控CSRF攻击的发生。
3) Anti CSRF Token
目前比较完善的解决方案是加入Anti-CSRF-Token。即发送请求时在HTTP 请求中以参数的形式加入一个随机产生的token,并在服务器建立一个拦截器来验证这个token。服务器读取浏览器当前域cookie中这个token值,会进行校验该请求当中的token和cookie当中的token值是否都存在且相等,才认为这是合法的请求。否则认为这次请求是违法的,拒绝该次服务。
这种方法相比Referer检查要安全很多,token可以在用户登陆后产生并放于session或cookie中,然后在每次请求时服务器把token从session或cookie中拿出,与本次请求中的token 进行比对。由于token的存在,攻击者无法再构造出一个完整的URL实施CSRF攻击。但在处理多个页面共存问题时,当某个页面消耗掉token后,其他页面的表单保存的还是被消耗掉的那个token,其他页面的表单提交时会出现token错误。
4) 验证码
应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。
点击劫持
点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。
1. 特点
2. 点击劫持的原理
用户在登陆 A 网站的系统后,被攻击者诱惑打开第三方网站,而第三方网站通过 iframe 引入了 A 网站的页面内容,用户在第三方网站中点击某个按钮(被装饰的按钮),实际上是点击了 A 网站的按钮。
接下来我们举个例子:我在优酷发布了很多视频,想让更多的人关注它,就可以通过点击劫持来实现
1iframe { 2width: 1440px; 3height: 900px; 4position: absolute; 5top: -0px; 6left: -0px; 7z-index: 2; 8-moz-opacity: 0; 9opacity: 0; 10filter: alpha(opacity=0); 11} 12button { 13position: absolute; 14top: 270px; 15left: 1150px; 16z-index: 1; 17width: 90px; 18height:40px; 19} 20</style> 21...... 22<button>点击脱衣</button> 23<img src="http://pic1.win4000.com/wallpaper/2018-03-19/5aaf2bf0122d2.jpg"> 24<iframe src="http://i.youku.com/u/UMjA0NTg4Njcy" scrolling="no"></iframe>
从上图可知,攻击者通过图片作为页面背景,隐藏了用户操作的真实界面,当你按耐不住好奇点击按钮以后,真正的点击的其实是隐藏的那个页面的订阅按钮,然后就会在你不知情的情况下订阅了。
3. 如何防御
1)X-FRAME-OPTIONS
X-FRAME-OPTIONS是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用 iframe 嵌套的点击劫持攻击。
该响应头有三个值可选,分别是
2)JavaScript 防御
对于某些远古浏览器来说,并不能支持上面的这种方式,那我们只有通过 JS 的方式来防御点击劫持了。
1<head> 2 <style id="click-jack"> 3 html { 4 display: none !important; 5 } 6 </style> 7</head> 8<body> 9 <script> 10 if (self == top) { 11 var style = document.getElementById('click-jack') 12 document.body.removeChild(style) 13 } else { 14 top.location = self.location 15 } 16 </script> 17</body> 以上代码的作用就是当通过 iframe 的方式加载页面时,攻击者的网页直接不显示所有内容了。
URL跳转漏洞
定义:借助未验证的URL跳转,将应用程序引导到不安全的第三方区域,从而导致的安全问题。
1.URL跳转漏洞原理
黑客利用URL跳转漏洞来诱导安全意识低的用户点击,导致用户信息泄露或者资金的流失。其原理是黑客构建恶意链接(链接需要进行伪装,尽可能迷惑),发在QQ群或者是浏览量多的贴吧/论坛中。
安全意识低的用户点击后,经过服务器或者浏览器解析后,跳到恶意的网站中。
恶意链接需要进行伪装,经常的做法是熟悉的链接后面加上一个恶意的网址,这样才迷惑用户。
诸如伪装成像如下的网址,你是否能够识别出来是恶意网址呢?
1http://gate.baidu.com/index?act=go&url=http://t.cn/RVTatrd 2http://qt.qq.com/safecheck.html?flag=1&url=http://t.cn/RVTatrd 3http://tieba.baidu.com/f/user/passport?jumpUrl=http://t.cn/RVTatrd
2.实现方式:
这里我们举个Header头跳转实现方式:
1<?php 2$url=$_GET['jumpto']; 3header("Location: $url"); 4?> 1http://www.wooyun.org/login.php?jumpto=http://www.evil.com
这里用户会认为www.wooyun.org都是可信的,但是点击上述链接将导致用户最终访问www.evil.com这个恶意网址。
3.如何防御
1)referer的限制
如果确定传递URL参数进入的来源,我们可以通过该方式实现安全限制,保证该URL的有效性,避免恶意用户自己生成跳转链接
2)加入有效性验证Token
我们保证所有生成的链接都是来自于我们可信域的,通过在生成的链接里加入用户不可控的Token对生成的链接进行校验,可以避免用户生成自己的恶意链接从而被利用,但是如果功能本身要求比较开放,可能导致有一定的限制。
SQL注入
SQL注入是一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库漏洞进行攻击。
1.SQL注入的原理
我们先举一个万能钥匙的例子来说明其原理:
1<form action="/login" method="POST"> 2 <p>Username: <input type="text" name="username" /></p> 3 <p>Password: <input type="password" name="password" /></p> 4 <p><input type="submit" value="登陆" /></p> 5</form>
后端的 SQL 语句可能是如下这样的:
1let querySQL = ` 2 SELECT * 3 FROM user 4 WHERE username='${username}' 5 AND psw='${password}' 6`; 7// 接下来就是执行 sql 语句... 8
这是我们经常见到的登录页面,但如果有一个恶意攻击者输入的用户名是 admin' --,密码随意输入,就可以直接登入系统了。why! ----这就是SQL注入。
我们之前预想的SQL 语句是:
1SELECT * FROM user WHERE username='admin' AND psw='password'
但是恶意攻击者用奇怪用户名将你的 SQL 语句变成了如下形式:
1SELECT * FROM user WHERE username='admin' --' AND psw='xxxx'
在 SQL 中,' --是闭合和注释的意思,-- 是注释后面的内容的意思,所以查询语句就变成了:
1SELECT * FROM user WHERE username='admin'
所谓的万能密码,本质上就是SQL注入的一种利用方式。
一次SQL注入的过程包括以下几个过程:
SQL注入的必备条件: 1.可以控制输入的数据 2.服务器要执行的代码拼接了控制的数据。
我们会发现SQL注入流程中与正常请求服务器类似,只是黑客控制了数据,构造了SQL查询,而正常的请求不会SQL查询这一步,SQL注入的本质:数据和代码未分离,即数据当做了代码来执行。
2.危害
3.如何防御
OS命令注入攻击
OS命令注入和SQL注入差不多,只不过SQL注入是针对数据库的,而OS命令注入是针对操作系统的。OS命令注入攻击指通过Web应用,执行非法的操作系统命令达到攻击的目的。只要在能调用Shell函数的地方就有存在被攻击的风险。倘若调用Shell时存在疏漏,就可以执行插入的非法命令。
命令注入攻击可以向Shell发送命令,让Windows或Linux操作系统的命令行启动程序。也就是说,通过命令注入攻击可执行操作系统上安装着的各种程序。
1.原理
黑客构造命令提交给web应用程序,web应用程序提取黑客构造的命令,拼接到被执行的命令中,因黑客注入的命令打破了原有命令结构,导致web应用执行了额外的命令,最后web应用程序将执行的结果输出到响应页面中。
我们通过一个例子来说明其原理,假如需要实现一个需求:用户提交一些内容到服务器,然后在服务器执行一些系统命令去返回一个结果给用户
1// 以 Node.js 为例,假如在接口中需要从 github 下载用户指定的 repo 2const exec = require('mz/child_process').exec; 3let params = {/* 用户输入的参数 */}; 4exec(`git clone ${params.repo} /some/path`); params.repo传入的是 https://github.com/admin/admin.github.io.git 确实能从指定的 git repo 上下载到想要的代码。
但是如果 params.repo 传入的是 https://github.com/xx/xx.git && rm -rf /* && 恰好你的服务是用 root 权限起的就糟糕了。
2.如何防御
参考资料
SpringBoot提供了一个页面,嵌入到前端的iframe页面中,打开才菜单后浏览器的控制台报错,如下:
frame because it set 'X-Frame-Options' to 'deny'.
页面嵌入iframe:
VUE,嵌入iframe,实现iframe的100%高度和宽度
HTTP响应头X-Frame-Options:
1、取值:DENY,页面不能被嵌入到任何iframe或者frame中。
2、取值:SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中。
3、取值:ALLOW-FROM uri:页面只能被嵌入到指定域名的框架中。
X-Frame-Options的安全问题:
点击劫持(ClickJacking),一种视觉上的欺骗手段,攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面,通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。
HTTP响应头信息中的X-Frame-Options,可以指示浏览器是否应该加载一个iframe中的页面,如果服务器响应头信息中没有X-Frame-Options,则该网站存在ClickJacking攻击风险。网站可以通过设置X-Frame-Options阻止站点内的页面被其他页面嵌入从而防止点击劫持。
配置类:
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
配置方法:
protected void configure(HttpSecurity http) throws Exception
配置代码:
此账号为华为云开发者社区官方运营账号,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态
本文分享自华为云社区《Web安全和浏览器跨域访问》,原文作者:kg-follower 。
今天说一说和前端相关的 Web 安全问题和开发过程中经常遇到的跨域问题。
基本原理
XSS(Cross-Site Scripting),跨站脚本攻击通过在用户的浏览器内运行非法的 HTML 标签或 JavaScript 进行的一种攻击。
攻击手段
攻击者往 Web 页面里插入恶意网页脚本代码,当用户浏览该页面时,嵌入 Web 页面里面的脚本代码会被执行,从而达到攻击者盗取用户信息或其他侵犯用户安全隐私的目的。
XSS 攻击分类
反射型 xss 攻击。通过给被攻击者发送带有恶意脚本的 URL 或将不可信内容插入页面,当 URL 地址被打开或页面被执行时,浏览器解析、执行恶意脚本。
反射型 xss 的攻击步骤:1. 攻击者构造出特殊的 URL 或特殊数据;2. 用户打开带有恶意代码的 URL 时,Web 服务器将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器;3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行;4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
防御:1.Web 页面渲染的所有内容或数据都必须来自服务端;2. 客户端对用户输入的内容进行安全符转义,服务端对上交内容进行安全转义;3.避免拼接 html。
存储型 xss。恶意脚本被存储在目标服务器上。当浏览器请求数据时,脚本从服务器传回浏览器去执行。
存储型 xss 的攻击步骤:1. 攻击者将恶意代码提交到目标网站的数据库中;2.用户浏览到目标网站时,前端页面获得数据库中读出的恶意脚本时将其渲染执行。
防御:防范存储型 XSS 攻击,需要我们增加字符串的过滤:前端输入时过滤;服务端增加过滤;前端输出时过滤。
通常有三种方式防御 XSS 攻击:1. ContentSecurity Policy(CSP)。CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。通常可以通过两种方式开启,例如只允许加载相同域下的资源:
设置 HTTP Header 中的 CSP(Content-Security-Policy: default-src 'self')
设置 meta 标签的方式(<meta http-equiv="Content-Security-Policy"content="form-action 'self';">)
转义字符
用户的输入永远不可信任的,最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义:
function escape(str) {
str = str.replace(/&/g, '&')
str = str.replace(/</g, '<')
str = str.replace(/>/g, '>')
str = str.replace(/"/g, '&quto;')
str = str.replace(/'/g, ''')
str = str.replace(/`/g, '`')
str = str.replace(/\//g, '/')
return str
}
但是对于显示富文本来说,显然不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。对于这种情况,通常采用白名单过滤的办法:
const xss = require('xss')
let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
console.log(html)
<h1>XSS Demo</h1><script>alert("xss");</script>
经过白名单过滤,dom 中包含的<script>标签将不会被执行。
HTTP-only Cookie
禁止 JavaScript 读取某些敏感 cookie,使得 cookie 只有 http 能够访问。
基本概念
CSRF(Cross-site request forgery 跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
CSRF 攻击类型
主动型攻击。用户访问网站 A 并在浏览器保存 A 的登录状态(cookie 等信息),攻击者诱导受害者访问网站 B,网站 B 含有访问 A 接口的恶意代码,受害者访问 B 时带着 A 的登录状态,攻击者便可以冒充用户执行对 A 的恶意操作。
被动型攻击。攻击者在网站 A 发布带有恶意链接的评论或内容(提交对 A 带有增删改的诱导型标签),当其他拥有登录状态的受害者点击评论的恶意链接时,就会冒用受害者登录凭证发起攻击。
CSRF 攻击防范
验证 HTTP Referer 字段。在 HTTP 头中有 Referer 字段,他记录该 HTTP 请求的来源地址,如果跳转的网站与来源地址相符,那就是合法的,如果不符则可能是 csrf 攻击,拒绝该请求。
SameSite。可以对 Cookie 设置 SameSite 属性。该属性表示 Cookie 不随着跨域请求发送,可以很大程度减少 CSRF 的攻击。
请求中加入 token。服务端给用户生成一个 token,加密后传递给用户,用户在提交请求时,需要携带这个 token,服务端发现 token 不存在或者 token 校验不成功,那么就拒绝该请求。
DNS 劫持
DNS 劫持就是通过劫持了 DNS 服务器,通过某些手段来取得某个域名的解析控制权,进而修改此域名的解析结果,导致对该域名的访问由原 IP 地址转入到修改后的 IP,其结果就是对特定的网站不能访问或访问的是假网址。
防御:使用 https 校验通信双方身份和数据完整性。
点击劫持
攻击者构建了一个非常有吸引力的网页,将被攻击的页面放置在当前页面的 iframe 中,使用样式将 iframe 叠加到非常有吸引力内容的上方,将 iframe 设置为 100%透明,其实就是通过覆盖不可见的页面,诱导用户点击而造成的攻击行为。
防御措施。1. X-FRAME-OPTIONS 设置允许 iframe 加载的域 2. 限制 iframe 页面中的 JavaScript 脚本执行。
无论是 xss、csrf 还是点击劫持,上面讨论的这几种攻击属于前端攻击,原因大多是开发者的脚本或模板代码存在不安全的隐患或是没有考虑网络传输安全问题。下面简单说一说恶意攻击利用网站后台漏洞发起的攻击。
SQL 注入漏洞存在的原因,就是拼接 SQL 参数。也就是将用于输入的查询参数,直接拼接在 SQL 语句中,恶意攻击者可以构造特殊的 sql 语句绕过安全验证。
SQL 注入条件:1.攻击者可以控制输入的数据;2.服务器要执行的代码拼接了被控制的数据。
SQL 注入防御。1. 严格限制 Web 应用的数据库的操作权限;2. 对进入数据库的特殊字符(’,”,,<,>,&,*,; 等)进行转义处理,或编码转换,类似防御 xss 攻击时对输入转义;3. 所有的查询语句建议使用数据库提供的参数化查询接口,如使用占位参数或对象关系映射 ORM。
DOS 攻击通过在网站的各个环节进行攻击,使得整个流程跑不起来,以达到瘫痪服务为目的。最常见的就是发送大量请求导致服务器过载宕机。DDOS 攻击的原理就是利用分布式的客户端,向目标发起大量看上去合法的请求,消耗/占用大量资源,从而达到拒绝服务的目的。
攻击方式:1.端口扫描;2.ping 洪水;3.SYN 洪水;4.FTP 跳转攻击;
DDOS 防范。1.在服务器上删除未使用的服务,关闭未使用的端口。2. 进行实时监控,封禁某些恶意密集型请求 IP 段;3. 进行静态资源缓存,隔离源文件的访问,比如 CDN 加速;4. 隐藏服务器的真实 IP 地址
同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。所谓同源是指“协议+域名+端口”三者均相同。
同源策略限制了客户端 js 代码的以下行为:
1.Cookie、LocalStorage 和 IndexDB 无法读取;
2.DOM 节点。来自一个源的 js 只能读写自己源的 DOM 树不能读取其他源的 DOM 树。如果两个网页不同源,就无法拿到对方的 DOM。典型的例子是 iframe 窗口和 window.open 方法打开的窗口,它们与父窗口无法通信。
网站不开启同源策略,钓鱼网站便可以使用 iframe 标签加载中国银行登录界面,执行脚本进而拿到用户名密码。
当设置了同源策略,父子窗口执行获取对方 DOM 时会报错。
3.AJAX 请求限制
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
除了架设服务器代理,还有以下几种方法规避同源限制:JSONP,WebSocket,CORS,本文详细讨论下后两种方法的实现。
WebSocket。WebSocket 是一种通信协议,使用 ws://(非加密)和 wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。Websocket 请求头信息包含一个 origin 字段,服务器根据这个字段判断是否允许本次通信。
CORS。CORS 跨域资源共享是 W3C 标准,是解决跨域 Ajax 请求的最常见解决方法。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
浏览器将 CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求:
(1) 请求方法是以下三种方法之一:HEAD、GET、POST
(2)HTTP 的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个 Origin 字段,该字段用来说明,本次请求来自哪个源。服务器根据这个值,决定是否同意这次请求。如果 Origin 指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。若该响应的头信息没有包含 Access-Control-Allow-Origin 字段,就抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获。若 Origin 指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。其中 Access-Control-Allow-Origin 字段是必须的。它的值要么是请求时 Origin 字段的值,要么是一个*,表示接受任意域名的请求。
对于非简单请求,在正式通信之前,会增加一次 HTTP 查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。
"预检"请求用的请求方法是 OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是 Origin,表示请求来自哪个源。
除了 Origin 字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method。该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法
(2)Access-Control-Request-Headers。该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段。
预检请求的回应。
服务器收到"预检"请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段以后,确认允许跨源请求,就可以做出回应。回应最关键的是 Access-Control-Allow-Origin 字段,表示允许该源的请求,若没有任何 CORS 相关头信息字段则说明服务器否认该请求。若服务器允许,则 Access-Control-Allow-Methods 字段是必须的,它的值是一个逗号分隔的字符串,表明服务器支持的方法。如果预检请求包含 Access-Control-Request-Headers 字段,则返回体中该字段也是必须的,它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。预检请求得到允许回应后,浏览器便发送正常 CORS 请求。
最近在开发一个前端 poc 项目时遇到了跨域资源访问被限制的问题,在本地启动 angular 项目,其他人可以通过 ip 访问到静态资源,发送 ajax 请求时被限制。于是想通过配置代理的方式解决这个跨域问题:在和 package.json 同级的目录中新建 proxy.conf.json 文件,target 字段是后端服务真实的 ip,changeOrigin 字段设置为 true,关闭 secure 字段。
{
"/": {
"target": "http://10.173.99.224:8081/",
"changeOrigin": true,
"secure": false,
"loglevel": "debug"
}
}
在 package.json 的启动命令中添加
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json --host 0.0.0.0",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
--host0.0.0.0 表示监听所有来源的主机。解决
点击关注,第一时间了解华为云新鲜技术~
*请认真填写需求信息,我们会在24小时内与您取得联系。