1. 程式人生 > >防盜鏈的實現原理以及相應的解決方法

防盜鏈的實現原理以及相應的解決方法

  1. 我的實現防盜鏈的做法,也是參考該位前輩的文章。基本原理就是就是一句話:通過判斷request請求頭的refer是否來源於本站。(當然請求頭是來自於客戶端的,是可偽造的,暫不在本文討論範圍內)。
  2. 首先我們去了解下什麼是HTTP Referer。簡言之,HTTP Referer是header的一部分,當瀏覽器向web伺服器傳送請求的時候,一般會帶上Referer,告訴伺服器我是從哪個頁面連結過來的,伺服器籍此可以獲得一些資訊用於處理。比如從我主頁上鍊接到一個朋友那裡,他的伺服器就能夠從HTTP Referer中統計出每天有多少使用者點選我主頁上的連結訪問他的網站。(注:該文所有用的站點均假設以
    http://blog.csdn.net
    為例)
    假如我們要訪問資源:http://blog.csdn.net/Beacher_Ma 有兩種情況:
    1. 我們直接在瀏覽器上輸入該網址。那麼該請求的HTTP Referer 就為null
    2. 如果我們在其他其他頁面中,通過點選,如 http://www.csdn.net 上有一個 http://blog.csdn.net/Beacher_Ma 這樣的連結,那麼該請求的HTTP Referer 就為http://www.csdn.net
  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; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

檔案/WEB-INF/classes/preventLink.properties
用於限制的url正則,用逗號分隔多個(在這裡我攔截了諸如
/csdn/index!beacher_Ma.action,/csdn/index!beacher_Ma.action?adsfdf)
url.limit=/.+/index/!.+//.action.*,/index/!.+.action?.+
這裡是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中縮寫攔截範圍,這個要看具體你要攔截什麼樣的請求,另外圖片防盜鏈,下載反盜鏈也是一樣的原理的。