防盜鏈的基本原理與實現

1.  個人實現防盜鏈的作法,也是參考該位前輩的文章。基本原理就是就是一句話:經過判斷request請求頭的refer是否來源於本站。(固然請求頭是來自於客戶端的,是可僞造的,暫不在本文討論範圍內)。css

2.  首先咱們去了解下什麼是HTTP Referer。簡言之,HTTP Referer是header的一部分,當瀏覽器向web服務器發送請求的時候,通常會帶上Referer,告訴服務器我是從哪一個頁面連接過來的,服務器籍此能夠得到一些信息用於處理。好比從我主頁上連接到一個朋友那裏,他的服務器就可以從HTTP Referer中統計出天天有多少用戶點擊我主頁上的連接訪問他的網站。(注:該文全部用的站點均假設以 http://blog.csdn.net爲例)html

假如咱們要訪問資源:http://blog.csdn.net/Beacher_Ma 有兩種狀況:java

1.  咱們直接在瀏覽器上輸入該網址。那麼該請求的HTTP Referer 就爲nullweb

2.  若是咱們在其餘其餘頁面中,經過點擊,如 http://www.csdn.net 上有一個 http://blog.csdn.net/Beacher_Ma 這樣的連接,那麼該請求的HTTP Referer 就爲http://www.csdn.netspring

3.  知道上述原理後,咱們能夠用Filter去實現這個防盜鏈功能。網上的作法可能是用列舉的方式去作的,而我這裏是用正則去作,相對比較靈活點,另外,我效仿了spring的filter作法,加了個shouldBeFilter的方法,考慮到,好比假如你要攔截*.Action的一部分方法,而不是所有時,咱們就能夠先看看請求的URL是否shouldBeFilter,若是不是的話,那麼就直接放行,在效率上有所提升。廢話不說,直接上代碼吧。瀏覽器

//防盜鏈filter服務器

public class PreventLinkFilter implements Filter {

    private static Logger logger = LoggerFactory

           .getLogger(PreventLinkFilter.class);

    // 限制訪問地址列表正則

    private static List<Pattern> urlLimit = new ArrayList<Pattern>();

    // 容許訪問列表

    private static List<String> urlAllow = new ArrayList<String>();

    // 錯誤地址列表

    private static String urlError = "";

 

    // 必須過Filter的請求

    protected boolean shouldBeFilter(HttpServletRequest request)

           throws ServletException {

       String path = request.getServletPath();

       for (int i = 0; i < urlLimit.size(); i++) {

           Matcher m = urlLimit.get(i).matcher(path);

           if (m.matches()) {

              logger.debug("當前的Path爲{}" + path + "必須進行過濾");

              return true;

           }

       }

       return false;

    }

 

    public void destroy() {

       // TODO Auto-generated method stub

 

    }

 

    public void doFilter(ServletRequest request, ServletResponse response,

           FilterChain chain) throws IOException, ServletException {

       HttpServletRequest httpRequest = (HttpServletRequest) request;

       HttpServletResponse httpResponse = (HttpServletResponse) response;

       if (null == httpRequest || null == httpResponse) {

           return;

       }

       // 放行不符合攔截正則的Path

       if (!shouldBeFilter(httpRequest)) {

           chain.doFilter(request, response);

           return;

       }

 

       String requestHeader = httpRequest.getHeader("referer");

       if (null == requestHeader) {

           httpResponse.sendRedirect(urlError);

           return;

       }

       for (int i = 0; i < urlAllow.size(); i++) {

           if (requestHeader.startsWith(urlAllow.get(i))) {

              chain.doFilter(httpRequest, httpResponse);

              return;

           }

       }

       httpResponse.sendRedirect(urlError);

       return;

    }

 

    public void init(FilterConfig fc) throws ServletException {

       logger.debug("防盜鏈配置開始...");

       String filename;

       try {

           filename = fc.getServletContext().getRealPath(

                  "/WEB-INF/classes/preventLink.properties");

           File f = new File(filename);

           InputStream is = new FileInputStream(f);

           Properties pp = new Properties();

           pp.load(is);

           // 限制訪問的地址正則

           String limit = pp.getProperty("url.limit");

           // 解析字符串,變成正則,放在urlLimit列表中

           parseRegx(limit);

           // 不受限的請求頭

           String allow = pp.getProperty("url.allow");

           // 將全部容許訪問的請求頭放在urlAllow列表中

           urlAllow = parseStr(urlAllow, allow);

           urlError = pp.getProperty("url.error");

       } catch (Exception e) {

           e.printStackTrace();

       }

 

    }

 

    private void parseRegx(String str) {

       if (null != str) {

           String[] spl = str.split(",");

           if (null != spl) {

              for (int i = 0; i < spl.length; i++) {

                  Pattern p = Pattern.compile(spl[i].trim());

                  urlLimit.add(p);

              }

           }

       }

 

    }

    private List<String> parseStr(List<String> li, String str) {

       if (null == str || str.trim().equals("")) {

           return null;

       }

       String[] spl = str.split(",");

       if (null != spl && spl.length > 0) {

           li = Arrays.asList(spl);

       }

       return li;

    }

}

 

文件/WEB-INF/classes/preventLink.properties網站

##用於限制的url正則,用逗號分隔多個(在這裏我攔截了諸如/csdn/index!beacher_Ma.action,/csdn/index!beacher_Ma.action?adsfdf)url

url.limit=/.+/index/!.+//.action.*,/index/!.+.action?.+spa

##這裏是Http Refer是否以指定前綴開始,前兩個是本地調試用的。。

url.allow=http://127.0.0.1,http://localhost,http://www.csdn.NET

##這裏是被盜鏈後,response到如下的錯誤頁面

url.error=http://www.csdn.net/error.html

參考文章:http://shen198623.javaeye.com/blog/243330

   這篇文章是攔截全部的請求的,他fileter中的url-pattern是/*,這樣的話,連/css /jpg等都話被filter攔截到,要麼在裏面進行shouldBeFilter的判斷,要麼就在url-pattern中縮寫攔截範圍,這個要看具體你要攔截什麼樣的請求,另外圖片防盜鏈,下載反盜鏈也是同樣的原理的。

來源:http://blog.csdn.net/beacher_ma/article/details/5559739

相關文章
相關標籤/搜索