共计 5948 个字符,预计需要花费 15 分钟才能阅读完成。
摘要: 本文探讨 web 前端平安问题以及应答措施,浏览器同源策略以及对资源跨域拜访的几种解决方案
本文分享自华为云社区《Web 平安和浏览器跨域拜访》,原文作者:kg-follower。
明天说一说和前端相干的 Web 平安问题和开发过程中常常遇到的跨域问题。
1.Web 平安
1.1 XSS
基本原理
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. Content Security Policy(CSP)。CSP 实质上就是建设白名单,开发者明确通知浏览器哪些内部资源能够加载和执行。咱们只须要配置规定,如何拦挡是由浏览器本人实现的。咱们能够通过这种形式来尽量减少 XSS 攻打。通常能够通过两种形式开启,例如只容许加载雷同域下的资源:
设置 HTTP Header 中的 CSP(Content-Security-Policy: default-src ‘self’)
设置 meta 标签的形式(<meta http-equiv=”Content-Security-Policy” content=”form-action ‘self’;”>)
2. 转义字符。用户的输出永远不可信赖的,最广泛的做法就是本义输入输出的内容,对于引号、尖括号、斜杠进行本义:
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 可能拜访。
1.2 CSRF
基本概念
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 校验不胜利,那么就回绝该申请。
1.3 流量劫持
DNS 劫持
DNS 劫持就是通过劫持了 DNS 服务器,通过某些伎俩来获得某个域名的解析控制权,进而批改此域名的解析后果,导致对该域名的拜访由原 IP 地址转入到批改后的 IP,其后果就是对特定的网站不能拜访或拜访的是假网址。
进攻:应用 https 校验通信单方身份和数据完整性。
点击劫持
攻击者构建了一个十分有吸引力的网页,将被攻打的页面搁置在以后页面的 iframe 中,应用款式将 iframe 叠加到十分有吸引力内容的上方,将 iframe 设置为 100% 通明,其实就是通过笼罩不可见的页面,诱导用户点击而造成的攻击行为。
进攻措施。1. X-FRAME-OPTIONS 设置容许 iframe 加载的域 2. 限度 iframe 页面中的 JavaScript 脚本执行。
无论是 xss、csrf 还是点击劫持,下面探讨的这几种攻打属于前端攻打,起因大多是开发者的脚本或模板代码存在不平安的隐患或是没有思考网络传输平安问题。上面简略说一说歹意攻打利用网站后盾破绽发动的攻打。
1.4 SQL 注入
SQL 注入破绽存在的起因,就是拼接 SQL 参数。也就是将用于输出的查问参数,间接拼接在 SQL 语句中,歹意攻击者能够结构非凡的 sql 语句绕过平安验证。
SQL 注入条件:1. 攻击者能够管制输出的数据;2. 服务器要执行的代码拼接了被管制的数据。
SQL 注入进攻。1. 严格限度 Web 利用的数据库的操作权限;2. 对进入数据库的特殊字符(’,”,,<,>,&,*,; 等)进行本义解决,或编码转换,相似进攻 xss 攻打时对输出本义;3. 所有的查问语句倡议应用数据库提供的参数化查问接口,如应用占位参数或对象关系映射 ORM。
1.5 DDOS 攻打
DOS 攻打通过在网站的各个环节进行攻打,使得整个流程跑不起来,以达到瘫痪服务为目标。最常见的就是发送大量申请导致服务器过载宕机。DDOS 攻打的原理就是利用分布式的客户端,向指标发动大量看上去非法的申请,耗费 / 占用大量资源,从而达到拒绝服务的目标。
攻击方式:1. 端口扫描;2.ping 洪水;3.SYN 洪水;4.FTP 跳转攻打;
DDOS 防备。1. 在服务器上删除未应用的服务,敞开未应用的端口。2. 进行实时监控,封禁某些歹意密集型申请 IP 段;3. 进行动态资源缓存,隔离源文件的拜访,比方 CDN 减速;4. 暗藏服务器的实在 IP 地址
3 跨域和同源策略
同源策略是一个重要的安全策略,它用于限度一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮忙阻隔歹意文档,缩小可能被攻打的媒介。所谓同源是指“协定 + 域名 + 端口”三者均雷同。
同源策略限度了客户端 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"
},
–host 0.0.0.0 示意监听所有起源的主机。解决
点击关注,第一工夫理解华为云陈腐技术~