能够在不从新加载整个网页的状况下,对网页的某部分进行更新。php
XMLHttpRequest 对象用于和服务器交换数据。(IE六、IE5不支持)css
let xhr = new XMLHttpRequest();
向服务器发送请求:html
功能:规定请求的类型、URL 以及是否异步处理请求。
参数:前端
- method :请求的类型,GET 或 POST。
- url:文件在服务器上的位置,该文件能够是任何类型的文件。
- async:true(异步)或 false(同步)
功能:将请求发送到服务器。
参数:git
- string :仅用于 POST 请求。
xhr.open("GET","/try/ajax/demo_get.php",true); xhr.send();
简单请求:github
xhr.open("POST","/try/ajax/demo_post.php",true); xhr.send();
POST 提交表单:
使用 setRequestHeader() 来添加 HTTP 头。而后在 send() 方法中规定但愿发送的数据。ajax
xhr.open("POST","/try/ajax/demo_post2.php",true); xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send("fname=Henry&lname=Ford");
功能:向请求添加 HTTP 头。
参数:算法
- header:规定头的名称。
- value:规定头的值。
如需得到来自服务器的响应,使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。数据库
属性 | 描述 | 备注 |
---|---|---|
responseText | 得到字符串形式的响应数据。 | 若是来自服务器的响应并不是XML,请使用responseText属性。 |
responseXML | 得到XML形式的响应数据。 | 若是来自服务器的响应是 XML且须要做为XML对象进行解析,请使用 responseXML 属性。 |
xhr.responseText xhr.responseXML
描述:存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
参数:express
- header:规定头的名称。
- value:规定头的值。
描述:存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
状态:
0
: 请求未初始化,尚未调用send()方法1
: 服务器链接已创建,已调用send()方法2
: 请求已接收,send()方法执行完成3
: 请求处理中,正在解析响应内容4
: 请求已完成,且响应已就绪
状态:
1xx
: 表示通知消息。2xx
: 表示成功。200
: 请求成功,已经正常处理完毕
3xx
: 表示重定向。
301
:永久性重定向。302
:临时性重定向。304
:请求被重定向到客户端本地缓存。
4xx
: 表示客户端差错。
400
:客户端请求存在语法错误。401
:客户端请求没有通过受权。403
:客户端的请求被服务器拒绝。404
:客户端请求的URL在服务器端不存在。
5xx
表示服务器差错
500
:服务端永久错误。
xhr.onreadystatechange=function(){ if (xmlhttp.readyState==4 && xmlhttp.status==200){ document.getElementById("myDiv").innerHTML=xmlhttp.responseText; } }
注意: onreadystatechange 事件被触发 4 次(0 - 4), 分别是: 0-一、1-二、2-三、3-4,对应着 readyState 的每一个变化。
callback()形式:
function ajax(url, callback) { let xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { callback(xhr.responseText); } }; xhr.send(); } let url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1"; ajax(url, function (data) { console.log(JSON.parse(data)); });
promise形式
function ajax(url) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { resolve(xhr.responseText); } }; xhr.send(); }); } let url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1"; ajax(url).then((res) => { console.log(JSON.parse(res)); }).catch((err) => { console.log(err); });
同源策略:是一种安全机制。同源策略限制从一个源加载的资源如何与来自另外一个源的资源进行交互。
同源:协议、主机、端口号都相同。
跨域:三者有一个不一样则是跨域。
非同源下:
Cookie
、LocalStorage
和 IndexDB
没法读取DOM
没法得到AJAX
请求不能发送跨域和跨站
同源策略做为浏览器的安全基石,其「同源」判断是比较严格的,相对而言,Cookie中的「同站」判断就比较宽松:只要两个 URL 的 eTLD+1 相同便可,不须要考虑协议和端口。其中,eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。eTLD+1 则表示,有效顶级域名+二级域名,例如 taobao.com 等。
举几个例子,www.taobao.com 和www.baidu.com是跨站,www.a.taobao.com 和www.b.taobao.com是同站,a.github.io 和 b.github.io 是跨站(注意是跨站)。
形成的问题:我的隐私泄露以及财产安全。包括:以你名义发送邮件,发消息,盗取你的帐号,甚至于购买商品,虚拟货币转帐
CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然能够保证一个请求是来自于某个用户的浏览器,但却没法保证该请求是用户批准发送的!
若是用户是登陆状态,打开了以下这样的页面:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>csrf攻击</title> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" name="viewport" /> </head> <body style="display: none;"> <form target="myIframe" id="csrf" action="https://www.kkkk1000.com/csrf/data/post_comment.php" metdod="POST"> <input type="text" name="content" value="csrf攻击" /> </form> <!-- iframe 用来防止页面跳转 --> <iframe id="myIframe" name="myIframe"></iframe> <script> var form = document.querySelector('#csrf'); form.submit(); </script> </body> </html>
就会自动在文章下发一条评论,这样就算完成了一次 CSRF 攻击。
固然,若是你把这个页面放服务器上,而后作成一个连接,用户点击这个连接,一样能够完成攻击。
1.SameSite属性
Cookie 的 SameSite
属性用来限制第三方 Cookie
,从而减小安全风险,能够用来防止 CSRF 攻击和用户追踪。
2.同源检测
在 HTTP 协议中,每个异步请求都会携带两个 Header ,用于标记来源域名:Origin Header
,Referer Header
。这两个 Header 在浏览器发起请求时,大多数状况会自动带上,而且不能由前端自定义内容。 服务器能够经过解析这两个 Header 中的域名,肯定请求的来源域。
3.验证码
而验证码会强制用户必须与应用进行交互,才能完成最终请求,并且由于 CSRF 攻击没法获取到验证码,所以一般状况下,验证码可以很好地遏制 CSRF 攻击。
4.Token 验证:
在 HTTP 请求中以参数的形式加入一个随机产生的 Token
,并在服务器端创建一个拦截器来验证这个 Token
,若是请求中没有 Token
或者 Token
内容不正确,则认为多是 CSRF
攻击而拒绝该请求。
添加 Token 验证的步骤:
一、服务器将 Token 返回到前端
用户打开页面时,前端发起请求,服务器会返回一个 Token,该 Token 经过加密算法对数据进行加密,通常 Token 都包括随机字符串和时间戳的组合,同时 Token 会存在服务器的 Session 中。以后页面加载完成时,使用 JS 遍历整个 DOM 树,在 DOM 中全部地址是本站的a
和form
标签中加入 Token,其余的请求就在编码时手动添加 Token 这个参数。
二、前端发请求时携带这个 Token
对于 GET 请求,Token 将附在请求地址以后,这样 URL 就变成http://url?token=tokenvalue
。 而对于form
标签发起的 POST 请求来讲,要在form
的最后加上:
<input type=”hidden” name=”token” value=”tokenvalue”/>
总之,就是前端发请求时把 Token 以参数的形式加入请求中。
三、服务器验证 Token 是否正确
当前端获得了 Token ,再次提交给服务器的时候,服务器须要判断 Token 的有效性,验证过程是先解密 Token,对比加密字符串以及时间戳,若是加密字符串一致且时间未过时,那么这个 Token 就是有效的。
攻击者在网页中嵌入客户端脚本(例如JavaScript), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的. 好比获取用户的Cookie,导航到恶意网站,携带木马等。
发出请求时,XSS代码出如今URL中,做为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一块儿传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,故叫反射型XSS。
演示:
index.ejs
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css'/> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %></p> <div class=""> <%- xss %> </div> </body> </html>
index.js
var express = require('express'); var router = express.Router(); router.get('/', function (req, res, next) { res.set("X-XSS-Protection", 0); //容许攻击 res.render('index', {title: 'Express', xss: req.query.xss}); }); module.exports = router;
请求
127.0.0.1:3000/?xss=<p%20onclick="alert(%27点我%27))">点我</p>
存储型XSS和反射型XSS的差异仅在于,提交的代码会存储在服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码。
XSS 通常利用js脚本读取用户浏览器中的cookie
,而若是在服务器端对某个cookie
设置了 httpOnly
属性,则没法经过 JS 脚本 读取到该cookie
的信息,但仍是能经过Application
中手动修改cookie
,因此只是在必定程度上能够防止XSS攻击,不是绝对的安全。
因为没有同源策略的限制,钓鱼网站能够直接拿到别的网站的Dom。
哪些html标签能绕过跨域?
经过href
、src
请求的资源不存在跨域问题,
<img src=跨域的图片地址/> //可用于统计打点,可以使用第三方统计服务 <link href=跨域的css地址/> <script src=跨域的js地址> </script> //<link /><script>可以使用CDN CDN通常都是外域 //<script>可实现JSONP
全部的跨域,都必须通过server端容许和配合,未经server端容许就实现跨域,说明浏览器有漏洞。
ajax请求不能跨域,因此引入jsonp 和 cors
JSONP的原理 :利用<script>
标签中 src
属性能够跨域的特性。
JSONP只支持GET
请求,由于本质上<script>
加载资源就是GET
。JSONP的优点在于支持老式浏览器,以及能够向不支持CORS的网站请求数据。
具体实现:
示例:
jsonp.html
<body> <script> function foo(data) { alert(data); } </script> <script src="http://localhost:8001/info?callback=foo"></script> </body>
serve.js
app.get("/info", async (req, res) => { let funcName = req.query.callback; res.send(`${funcName}('你好')`); //foo('你好'); });
CORS是一个W3C标准,全称是"跨域资源共享"。CORS有两种请求,简单请求和非简单请求。
只要同时知足如下两大条件,就属于简单请求。
(1) 请求方法是如下三种方法之一:HEAD
、GET
、POST
(2) HTTP的头信息不超出如下几种字段:Accept
、Accept-Language
、Content-Language
、Last-Event-ID
、Content-Type
:
Content-Type 只限于三个值application/x-www-form-urlencoded
、multipart/form-data
、text/plain
原理:
浏览器若发现此次跨源ajax请求是简单请求,就自动在头信息之中,添加一个Origin
字段,用来讲明,本次请求来自哪一个源
(协议 + 域名 + 端口)(前端实际上什么也不用干)。服务器根据这个值,决定是否赞成此次请求。
Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段(详见下文),就知道出错了,从而抛出一个错误,被 XMLHttpRequest
的 onerror
回调函数捕获。注意,这种错误没法经过状态码识别,由于HTTP回应的状态码有多是200。Origin
指定的源,在许可范围内,服务器返回的响应,会多出几个头信息字段。app.get("/",function(req,res){ //设置服务器端返回的响应的头字段 res.header("Access-Control-Allow-Origin","*"); res.send("你好"); })
Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求。
请求头 origin
对应响应头 Access-Control-Allow-Origin
在发送真正的请求前会提早发送一次options
请求(嗅探、预检请求),返回码是204
,预检测经过才会真正发出请求,这才返回200
。若是options
得到的回应是拒绝性质的(或者没有权限),会中止发送实际请求信息。这里经过前端发请求的时候增长一个额外的headers
来触发非简单请求。XHR
会根据返回的Access-Control-*
等头信息判断是否有对指定站点的访问权限,检查该请求是不是可靠安全的。
"预检"请求的头信息
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
(1) Origin
: 用来讲明,本次请求来自哪一个源
(2) Access-Control-Request-Method
: 该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT
。
(3)Access-Control-Request-Headers
: 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header
。
"预检"请求的响应
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
(1) Access-Control-Allow-Origin
: 表示http://api.bob.com
能够请求数据。该字段也能够设为星号,表示赞成任意跨源请求。与响应头 origin
对应。
(2) Access-Control-Allow-Methods
: 代表服务器支持的全部跨域请求的方法。与响应头Access-Control-Request-Method
对应。
(3)Access-Control-Allow-Headers
: 代表服务器支持的全部头信息字段。与响应头Access-Control-Request-Headers
对应。
一旦服务器经过了"预检"请求,之后每次浏览器正常的CORS请求,就都跟简单请求同样,会有一个Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。
示例:
前端
fetch(`http://localhost:9871/api/cors?msg=helloCors`, { // 须要带上cookie credentials: 'include', // 这里添加额外的headers来触发非简单请求 headers: { 't': 'extra headers' } }).then(res => { console.log(res) })
后台
const cors= require('koa2-cors); //配置 jsonp 的中间件 app.use(cors());
参考文章:https://segmentfault.com/a/11...
参考文章:http://www.ruanyifeng.com/blo...
*参考文章:跨站请求伪造—CSRF