能夠在不從新加載整個網頁的狀況下,對網頁的某部分進行更新。
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