跨域漏洞Response header配置 Access-Control-Allow-Origin

瀏覽器只允許請求當前域的資源,而對其他域的資源表示不信任。那怎麼纔算跨域呢?

  1. 請求協議http,https的不同
  2. domain的不同
  3. 端口port的不同

好好好,大概就是這麼回事啦,下面我們講2種中規中矩的辦法:CORSJSONP
document.domain,window.name,web sockets就先別鬧了,腰不好 : )

2、CORS

這是W3C的標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。我們先來看看整個流程

在此之前,需要知道簡單請求 複雜請求這兩個小朋友

1.簡單請求:
    1): 請求方式只能是:headgetpost
    2): 請求頭允許的字段:AcceptAccept-LanguageContent-LanguageLast-Event-ID
   Content-Type:application/x-www-form-urlencoded、multipart/form-data、text/plain 三選一

2.複雜請求:除了簡單請求的其他情況

請求頭origin字段爲當前域

服務器:誒,你是誰,我來看看你的origin,嗯嗯,可以,符合我的要求,放行!順便告訴你,老夫的規矩!

 


其中,最重要的就是Access-Control-Allow-Origin,標識允許哪個域的請求。當然,如果服務器不通過,根本沒有這個字段,接着觸發XHRonerror,再接着你就看到瀏覽器的提示xxx的服務器沒有響應Access-Control-Allow-Origin字段

 

//指定允許其他域名訪問
'Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(*,指定域,動態設置),3是因爲*不允許攜帶認證頭和cookies
//是否允許後續請求攜帶認證信息(cookies),該值只能是true,否則不返回
'Access-Control-Allow-Credentials:true'

上面第一行說到的Access-Control-Allow-Origin有多種設置方法:

  1. 設置*是最簡單粗暴的,但是服務器出於安全考慮,肯定不會這麼幹,而且,如果是*的話,遊覽器將不會發送cookies,即使你的XHR設置了withCredentials
  2. 指定域,如上圖中的http://172.20.0.206,一般的系統中間都有一個nginx,所以推薦這種
  3. 動態設置爲請求域,多人協作時,多個前端對接一個後臺,這樣很方便

withCredentials:表示XHR是否接收cookies和發送cookies,也就是說如果該值是false,響應頭的Set-Cookie,瀏覽器也不會理,並且即使有目標站點的cookies,瀏覽器也不會發送。

複雜請求:

最常見的情況,當我們使用putdelete請求時,瀏覽器會先發送option(預檢)請求,不過有時候,你會發現並沒有,這是後面我們會講到緩存。

預檢請求

與簡單請求不同的是,option請求多了2個字段:
Access-Control-Request-Method:該次請求的請求方式
Access-Control-Request-Headers:該次請求的自定義請求頭字段

服務器檢查通過後,做出響應:

//指定允許其他域名訪問
'Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(*,指定域,動態設置),3是因爲*不允許攜帶認證頭和cookies
//是否允許後續請求攜帶認證信息(cookies),該值只能是true,否則不返回
'Access-Control-Allow-Credentials:true'
//預檢結果緩存時間,也就是上面說到的緩存啦
'Access-Control-Max-Age: 1800'
//允許的請求類型
'Access-Control-Allow-Methods:GET,POST,PUT,POST'
//允許的請求頭字段
'Access-Control-Allow-Headers:x-requested-with,content-type'

這裏有個注意點:Access-Control-Request-MethodAccess-Control-Request-Headers返回的是滿足服務器要求的所有請求方式,請求頭,不限於該次請求.

問題所在:

1. 避免將Access-Control-Allow-Origin設置爲null和*
2. 禁止直接反射HTTP請求頭中的Origin字段值。對請求頭Origin值做嚴格過濾、校驗。具體來說,可以使用“全等於”判斷,或使用嚴格的正則(如:^
https://domain\.qq\.com$)進行判斷

設置 Access-Control-Allow-Origin 有多種方式,這裏寫兩種

一. 微服務中整合springSecurity,

1.編寫過濾器

package com.wf.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
@Slf4j
public class CORSFilter implements Filter {

    @Value("${allow.origin.regex}") //apollo配置 ,允許跨域訪問的主體
    private String originRegex;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", originRegex);
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(request, response);
    }

    public void destroy() {}

}

2.添加過濾器

package com.wf.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity security) throws Exception {
        security.csrf().disable();
        security.headers().frameOptions().disable();
        //加入過濾器
        security.addFilterBefore(new CORSFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

2. nginx 配置

location / {  
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Headers "X-Requested-With";
  add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
} 

如果同時配置服務器過濾器與nginx ,則會看到頁面錯誤:

The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed

看上面錯誤提示,contains multiple values "*" 意思就是設置了2次跨域,但是隻有一個是允許的,移除其中的任意一個就好了。如果服務器設置了允許跨域,使用Nginx代理裏面就不需要了(或者就不用使用Nginx了) 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章