來(lái)源:http://mp.weixin.qq.com/s?__biz=MjM5NTM1NDcyOQ==&mid=202557064&idx=1&sn=d24349248e5dd70e0d0bcdc0fb6e6ca5#rd
在前后端分離架構(gòu)下忧侧,難免會(huì)遇到跨域問(wèn)題酒甸。但是對(duì)于跨域,很多人并沒(méi)有多么深入的了解螟够。這里我就詳細(xì)講一下這個(gè)問(wèn)題。
同源策略與跨域
所謂跨域玫坛,英文叫做cross-domain滋觉,是網(wǎng)絡(luò)安全領(lǐng)域的一個(gè)專(zhuān)有名詞。簡(jiǎn)單點(diǎn)理解就是某些操作越過(guò)了域名的界限昌渤,訪問(wèn)了別的域名赴穗。
如果腳本可以自由訪問(wèn)其他域,就會(huì)產(chǎn)生很多安全問(wèn)題膀息。
比如般眉,假設(shè)有一個(gè)網(wǎng)上銀行系統(tǒng),你已經(jīng)登錄過(guò)了潜支,它支持一個(gè)ajax api可以進(jìn)行轉(zhuǎn)賬甸赃;有一個(gè)論壇系統(tǒng),人氣很高冗酿,但是其中有惡意腳本埠对,這個(gè)腳本會(huì)調(diào)用這個(gè)ajax api,從當(dāng)前登錄的用戶賬戶中裁替,轉(zhuǎn)1000塊到攻擊者的賬戶项玛。這樣,當(dāng)你訪問(wèn)這個(gè)論壇的時(shí)候弱判,就會(huì)被轉(zhuǎn)走1000塊襟沮,而你一點(diǎn)都不知道!
除此之外昌腰,跨域請(qǐng)求還有很多危害开伏。這不是一本關(guān)于安全的書(shū),也就不展開(kāi)講了遭商,想深入了解的可以買(mǎi)一本余弦編寫(xiě)的《Web前端黑客技術(shù)揭秘》硅则。
為了防范跨域攻擊,所有現(xiàn)代瀏覽器都遵循一套同源策略株婴。根據(jù)MDN上的定義怎虫,“如果兩個(gè)頁(yè)面擁有相同的協(xié)議(protocol)暑认,端口(如果指定),和主機(jī)大审,那么這兩個(gè)頁(yè)面就屬于同一個(gè)源(origin)”蘸际。對(duì)于違反同源策略的請(qǐng)求,除了img src等少數(shù)嵌入操作之外徒扶,都會(huì)被瀏覽器阻止粮彤。
這里需要注意的是:同源不僅僅要求相同的域名或ip,連協(xié)議和端口也必須相同姜骡。比如https://localhost和http://localhost或http://localhost:3000就不是同源的导坟,而http://localhost/api和http://localhost/views是同源的。
我們平常所說(shuō)的“跨域”其實(shí)就是指“發(fā)起不同源請(qǐng)求”圈澈,而這樣的跨域請(qǐng)求會(huì)被瀏覽器阻止惫周。
同源策略對(duì)保障互聯(lián)網(wǎng)安全有著非常重要的作用,很多安全策略都是基于同源策略的康栈。但是递递,這種同源策略會(huì)對(duì)前后端分離架構(gòu)下的開(kāi)發(fā)過(guò)程帶來(lái)很大困擾。比如啥么,即使是本地服務(wù)器登舞,也沒(méi)法和前端開(kāi)發(fā)服務(wù)器運(yùn)行在同一個(gè)端口上,這時(shí)候悬荣,跨域是必然的菠秒。而如果要讓后端程序同時(shí)提供web服務(wù),則很難發(fā)揮前端工具鏈的輕量級(jí)優(yōu)勢(shì)氯迂。那么稽煤,如何解決跨域問(wèn)題呢?
如何解決跨域問(wèn)題囚戚?
JSONP方式
最初用來(lái)解決跨域問(wèn)題的方式酵熙,叫做JSONP,它的基本原理是:跨域的“資源嵌入”是被瀏覽器允許的驰坊。所以匾二,可以通過(guò)一個(gè)script標(biāo)簽來(lái)嵌入一段來(lái)自其他服務(wù)器的腳本。由于這個(gè)腳本完全運(yùn)行在當(dāng)前域拳芙,無(wú)法訪問(wèn)第三方服務(wù)器的cookie等敏感信息察藐,所以是安全的。
JSONP的缺點(diǎn)是它只能支持GET操作舟扎,沒(méi)法支持POST等操作分飞,但是由于兼容性好等優(yōu)點(diǎn),仍然有很多網(wǎng)站采用JSONP的方式公開(kāi)自己的API供第三方調(diào)用睹限。
在Angular中譬猫,$http內(nèi)置了對(duì)JSONP的支持讯檐,它的調(diào)用接口也和其他方法沒(méi)什么區(qū)別,使用起來(lái)非常簡(jiǎn)單染服。
反向代理方式
要想解決跨域問(wèn)題别洪,最簡(jiǎn)單徹底的方法當(dāng)然是把他們拉到一個(gè)域下,而這就是該“反向代理”發(fā)揮作用的時(shí)候了柳刮。
所謂反向代理挖垛,就是在自己的域名下架設(shè)一個(gè)Web服務(wù)器,這個(gè)服務(wù)器會(huì)把請(qǐng)求轉(zhuǎn)發(fā)給第三方服務(wù)器秉颗,然后把結(jié)果返回給客戶端痢毒。
這時(shí)候,在客戶端看來(lái)蚕甥,自己就是在和這臺(tái)反向代理服務(wù)器打交道哪替,而不知道第三方服務(wù)器的存在。
所以梢灭,如果有一個(gè)Web服務(wù)程序,它同時(shí)提供了反向代理功能和靜態(tài)文件服務(wù)功能蒸其,靜態(tài)文件服務(wù)負(fù)責(zé)渲染前端頁(yè)面敏释,反向代理則提供對(duì)第三方服務(wù)器的透明訪問(wèn)。那么前端和后端就變成了同源的摸袁,不再受同源策略的約束钥顽。
那么,有這樣的Web服務(wù)程序嗎靠汁?有蜂大,而且不止一個(gè)。事實(shí)上蝶怔,幾乎所有的主流Web服務(wù)器都提供了反向代理功能奶浦。這里僅以nginx為例來(lái)示范反向代理的配置方式,其他Web服務(wù)器請(qǐng)搜相應(yīng)的文檔自行研究踢星。
server {
listen 80;
server_name your.domain.name;
location / {
proxy_pass http://localhost:5000/; # 把根路徑下的請(qǐng)求轉(zhuǎn)發(fā)給前端工具鏈(如gulp)打開(kāi)的開(kāi)發(fā)服務(wù)器澳叉,如果是產(chǎn)品環(huán)境,則使用root等指令配置為靜態(tài)文件服務(wù)器
}
location /api/ {
proxy_pass http://localhost:8080/service/; # 吧 /api 路徑下的請(qǐng)求轉(zhuǎn)發(fā)給真正的后端服務(wù)器
proxy_set_header Host $http_host;? # 把host頭傳過(guò)去沐悦,后端服務(wù)程序?qū)⑹盏統(tǒng)our.domain.name成洗,否則收到的是localhost:8080
proxy_cookie_path /api /service;?? # 把cookie中的path部分從/api替換成/service
proxy_cookie_domain localhost:8080 your.domain.name; # 把cookie的path部分從localhost:8080替換成your.domain.name
}
}
注意最后這兩句話,由于cookie中存在一個(gè)path機(jī)制藏否,可以對(duì)同一個(gè)域下的不同子域進(jìn)行區(qū)分瓶殃。所以,如果后端所使用的路徑是/service副签,而前端使用的路徑是/api遥椿,那么前端將不能訪問(wèn)后端的cookie基矮,這就導(dǎo)致登錄等操作所寫(xiě)入的cookie無(wú)法正常傳入傳出,其表現(xiàn)則是登錄始終沒(méi)有效果修壕。cookie的domain機(jī)制也是類(lèi)似的原理愈捅。
現(xiàn)實(shí)中的后端服務(wù)器,使用path機(jī)制的很多慈鸠,所以這項(xiàng)設(shè)置非常實(shí)用蓝谨。
CORS方式
這是W3C提供的另一種跨域方式。作為一項(xiàng)標(biāo)準(zhǔn)的跨域規(guī)范青团,CORS本應(yīng)該是最值得采用的譬巫。 問(wèn)題在于,老式瀏覽器不支持CORS督笆,而我們顯然還沒(méi)到可以無(wú)視老式瀏覽器的時(shí)候芦昔。 所以,只要有可能娃肿,就應(yīng)該優(yōu)先采用反向代理的方式咕缎。
CORS的原理是基于服務(wù)方授權(quán)的模式,也就是說(shuō)提供服務(wù)的程序要主動(dòng)通過(guò)CORS回應(yīng)頭來(lái)聲明自己信任哪些源(協(xié)議+域名+端口)料扰。 由于得到了服務(wù)方的授權(quán)凭豪,瀏覽器就可以放行來(lái)自這些域的請(qǐng)求了。
參考:http://www.cnblogs.com/mashch/articles/4261448.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
http://www.tuicool.com/articles/3q2iaqb
前后臺(tái)分離晒杈,nodeJS轉(zhuǎn)發(fā)請(qǐng)求實(shí)現(xiàn)跨域訪問(wèn):http://blog.csdn.net/u011783224/article/details/52214949