反饋已提交

網絡繁忙

Java防盜鏈在報表上面的應用

1. 描述

使用防盜鏈,來預防報表工程裏的報表被直接存取或者被其他網站連結存取。

注1:FineReport 11.0.12 版本新增 Referer 校驗功能,可參考 Referer校驗 進行配置,操作簡單,無需處理複雜程式碼。

注2:需先將 webroot 目錄部署在外置 Tomcat 下才可生效(內建設計器的 Tomcat 現在不讀 web.xml 了)。

注3:行動端存取也能起到防盜鏈作用。

2. 原理

瀏覽器中直接輸入報表 URL 的時候,它的頭檔案是空的,因此,可以在存取的時候做兩個判斷:頭檔案是否為空以及以什麼頁面進行跳轉,如果不符合跳到錯誤頁面即可。

1)什麼是 Referer?

這裏的 Referer 指的是 HTTP 頭部的一個欄位,也稱為 HTTP 來源地址(HTTP Referer),用來表示從哪兒連結到目前的網頁,採用的格式是 URL。換句話說,藉着 HTTP Referer 頭部網頁可以檢查訪客從哪裏而來,這也常被用來對付僞造的跨網站請求。

2)什麼是空 Referer,什麼時候會出現空 Referer?

首先,我們對空 Referer 的定義為,Referer 頭部的內容為空,或者,一個 HTTP 請求中根本不包含 Referer 頭部。

那麼什麼時候 HTTP 請求會不包含 Referer 欄位呢?根據 Referer 的定義,它的作用是指示一個請求是從哪裏連結過來,那麼當一個請求並不是由連結觸發產生的,那麼自然也就不需要指定這個請求的連結來源。

比如,直接在瀏覽器的地址欄中輸入一個資源的 URL 地址,那麼這種請求是不會包含 Referer 欄位的,因為這是一個“憑空產生”的 HTTP 請求,並不是從一個地方連結過去的。

那麼在防盜鏈設定中,允許空 Referer 和不允許空 Referer 有什麼差別?

在防盜鏈中,如果允許包含空的 Referer,那麼透過瀏覽器地址欄直接存取該資源 URL 是可以存取到的;

但如果不允許包含空的 Referer,那麼透過瀏覽器直接存取也是被禁止的。

3. 操作步驟

3.1 新增 class 檔案

編寫一個類檔案,用來判斷頭檔案是否為空,程式碼如下:

package com.fr.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public  class Dodo implements Filter {
    public void destroy() {
        // TODO Auto-generated method stub
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        String referer = req.getHeader("referer");
        //下面的IP地址是正常頁面請求
        if(null != referer && (referer.trim().startsWith("http://localhost:8080")||referer.trim().startsWith("http://dev.fanruan.com/detail.html"))){
            System.out.println("正常頁面請求"+referer);
            chain.doFilter(req, resp);
            //下面的就是出現不是正常頁面請求的時候跳轉
        }else{
            System.out.println("盜鏈"+referer);
            req.getRequestDispatcher("/LdapLogin.jsp").forward(req, resp);
        }
    }
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
    }
}

注:條件語句說明如下

null != referer 表示 referer 不為空。

referer.trim().startsWith("http://localhost:8080") 指被存取的伺服器地址,這句判斷一定要有,因為正常存取狀態下允許存取的連結跳轉過來存取該連結開頭的地址時,有兩條申請,一個就是對該伺服器的申請,如下圖所示。此句表示允許存取以 http://localhost:8080 開頭的連結。

referer.trim().startsWith("http://dev.fanruan.com/detail.html") 此處地址 IP 或埠號不能與被存取的伺服器地址相同,表示允許該連結跳轉到以 localhost:8080 開頭的連結地址來進行存取。

將 Dodo.java 編譯成 class 檔案,並放在%TOMCAT_HOME%\webroot\WEB-INF\classes\com\fr\test目錄下。


3.2 修改 web.xml 檔案

開啟%TOMCAT_HOME%\webapps\webroot\WEB-INF下建立 web.xml 檔案,配置一個過濾 filter,在出現 decision 的時候執行過濾,程式碼如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
   version="2.4">
  <display-name>Template WebApp</display-name>
    <mime-mapping>
  <extension>msi</extension>
  <mime-type>application/x-msi</mime-type>
  </mime-mapping>
  <filter>
  <filter-name>AuthFilter</filter-name>
  <filter-class>com.fr.test.Dodo</filter-class>
</filter>
  <filter-mapping>
  <filter-name>AuthFilter</filter-name>
  <url-pattern>/decision/*</url-pattern>
  </filter-mapping>
</web-app>

兩步就可以搞定了,如果屬於盜鏈,則跳轉至上述的 LDAPLogin 錯誤頁面,這裏沒有 LDAPLoign 頁面,所以直接跳轉 404。如果還想實現資料權限,則可以透過單點登入或者 Session 注入的方式。

4. 效果測試

準備兩個 HTML 檔案,放在外網 http://dev.fanruan.com/ 伺服器資料夾下。

注:在 IE 瀏覽器下,自帶超連結 FR.doHyperlinkByGet() 和 window.open() 方法跳轉的連結沒有 referer 屬性,會造成了防盜鏈失敗,可以使用表單 post 提交或者 a 標籤來完成跳轉。

假設 http://dev.fanruan.com/detail.html是正確的地址

<html>
<body>
<a href='http://localhost:8080/webroot/decision/view/report?viewlet=test.cpt'>防盜鏈測試,正確的連結地址</p>地址:http://localhost:8080/webroot/decision/view/report?viewlet=test.cpt</a>
</body>
<html>

假設 http://dev.fanruan.com是盜鏈的地址

<html>
<body><a href='http://localhost:8080/webroot/decision/view/report?viewlet=test.cpt'>防盜鏈測試,錯誤的連結地址</p>地址:http://localhost:8080/webroot/decision/view/report?viewlet=test.cpt</a>
</body>
</html>

4.1 情況一

透過http://dev.fanruan.com/detail.html跳轉,跳轉連結正確,即 referer 不為空且正確

4.2 情況二

透過http://dev.fanruan.com跳轉,跳轉連結錯誤,即 referer 不為空且錯誤

4.3 情況三

直接存取 URL 地址,即 referer 為空

5. 注意事項

在 IE 瀏覽器下,自帶超連結 FR.doHyperlinkByGet() 和 window.open() 方法跳轉的連結沒有 referer 屬性,會造成了防盜鏈失敗,可以使用表單 post 提交或者 a 標籤來完成跳轉。

上述是以 a 標籤跳轉連結為例,準備的兩個 html 檔案,放在外網 www.finereporthelp.com 伺服器資料夾下的。

這裏提供 post 提交方法,兩個 HTML 檔案內容為:

<html>
  <head>  
  <title>FineReport Demo</title>  
  <meta http-equiv="Content-Type" content="text/html; charset=GBK" />  
  <script type="text/javascript">
    function post(URL, PARAMS,target) { var temp_form = document.createElement("form");    
            temp_form .action = URL;    
            temp_form .target = target;
            temp_form .method = "post";    
            temp_form .style.display = "none"; for (var x in PARAMS) { var opt = document.createElement("textarea");    
                opt.name = x;    
                opt.value = PARAMS[x];    
                temp_form .appendChild(opt);    
            }    
            document.body.appendChild(temp_form);    
            temp_form .submit();   
        }
  </script>
  </head>  
  <body>
<p>測試</p>  
<input type="button" name="show" value="查詢" onclick="post('/webroot/decision/view/report',{reportlet:'test.cpt',a:'111'},'_blank')"/>  
  </body>  
</html>

同樣可以實現防盜鏈的效果。



附件列表


主題: 部署集成
  • 有幫助
  • 沒幫助
  • 只是瀏覽
  • 圖片不清晰
  • 用語看不懂
  • 功能說明看不懂
  • 操作說明太簡單
  • 內容有錯誤
中文(繁體)

滑鼠選中內容,快速回饋問題

滑鼠選中存在疑惑的內容,即可快速回饋問題,我們將會跟進處理。

不再提示

10s後關閉

獲取幫助
線上支援
獲取專業技術支援,快速幫助您解決問題
工作日9:00-12:00,13:30-17:30在线
頁面反饋
針對當前網頁的建議、問題反饋
售前咨詢
業務咨詢
電話:0933-790886或 0989-092892
郵箱:taiwan@fanruan.com
頁面反饋
*問題分類
不能為空
問題描述
0/1000
不能為空

反馈已提交

网络繁忙