企业提供下载链接的安全解决方案
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                企业提供下载链接的安全解决方案
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                ????????有時候我們在項目里面有需要提供給外界下載東西的鏈接(如先讓用戶下載我們給定的模板,然后讓用戶填完之后再上傳)這時我們不得不對外開放我們的資源路徑,如果用最簡單的方式將項目內的資源路徑暴露在頁面供用戶下載就涉及到了安全隱患,不法分子可能會根據我們提供的路徑猜測到其他路徑進行非法操作等等。
下面,介紹自己親測可行的解決方案:
先貼上整個Demo的目錄結構:
借用一個對url進行加密解密的工具類UrlUtil:
package com.zy.web.common;import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import java.security.SecureRandom;public class UrlUtil {private static final String KEY = "myYouMw6qPt&3AD";//這個KEY值可以任意指定,相當于一個密鑰private static final Logger LOGGER = LoggerFactory.getLogger(UrlUtil.class);public static String enCryptAndEncode(String content) {try {byte[] sourceBytes = enCryptAndEncode(content, KEY);return Base64.encodeBase64URLSafeString(sourceBytes);} catch (Exception e) {LOGGER.error(e.getMessage(), e);return content;}}/*** 加密函數** @param content 加密的內容* @param strKey 密鑰* @return 返回二進制字符數組* @throws Exception*/public static byte[] enCryptAndEncode(String content, String strKey) throws Exception {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");keyGenerator.init(128, new SecureRandom(strKey.getBytes()));SecretKey desKey = keyGenerator.generateKey();Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, desKey);return cipher.doFinal(content.getBytes("UTF-8"));}public static String deCryptAndDecode(String content) throws Exception {byte[] targetBytes = Base64.decodeBase64(content);return deCryptAndDecode(targetBytes, KEY);}/*** 解密函數** @param src 加密過的二進制字符數組* @param strKey 密鑰* @return* @throws Exception*/public static String deCryptAndDecode(byte[] src, String strKey) throws Exception {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");keyGenerator.init(128, new SecureRandom(strKey.getBytes()));SecretKey desKey = keyGenerator.generateKey();Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.DECRYPT_MODE, desKey);byte[] cByte = cipher.doFinal(src);return new String(cByte, "UTF-8");} }web.xml中配置springmvc的兩種常用的攔截方式
<!-- springMVC前端控制器 --><servlet><servlet-name>DownloadDemo</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- contextConfigLocation不是必須的, 如果不配置contextConfigLocation, springmvc的配置文件默認在:WEB-INF/servlet的name+"-servlet.xml" --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DownloadDemo</servlet-name><!-- 攔截所有請求jsp除外 --><url-pattern>/</url-pattern></servlet-mapping><servlet-mapping><servlet-name>DownloadDemo</servlet-name><url-pattern>*.action</url-pattern></servlet-mapping>在跳轉到有下載鏈接的頁面之前,在controller中進行如下處理:
package com.zy.web.controller;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;import com.zy.web.common.UrlUtil;@Controller @RequestMapping("/page") public class PageController {@RequestMapping("/toDownloadPage")public String toDownloadPage(HttpServletRequest request){String path = "/files/我的文件.docx";//這里指定頁面上供用戶下載的文件路徑 我這里是從webapp目錄下開始String pathEn = UrlUtil.enCryptAndEncode(path);request.setAttribute("path", pathEn);return "download/downloadPage";}}在有下載鏈接的頁面中,該有鏈接的地方做如下處理:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>下載頁面</title> </head> <body><a href="${pageContext.request.contextPath}/download/${path}">下載資源1</a><br/><a href="${pageContext.request.contextPath}/download1/test.action?url=${path}">下載資源2</a> </body> </html>啟動項目后訪問該頁面效果如下:(親測兼容IE7及以上) ?這樣就很難猜測項目的其他路徑
然后當用戶點擊下載鏈接,后臺controller應該這樣處理:
Restfull風格的url對應的后臺處理:
package com.zy.web.controller;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;import com.zy.web.common.UrlUtil;@Controller public class DownloadController{private static final Logger logger = LoggerFactory.getLogger(DownloadController.class);@RequestMapping("/download/{param}")public void downloadFile(HttpServletRequest request,HttpServletResponse response,@PathVariable("param") String param){InputStream fis = null;BufferedInputStream bis = null;BufferedOutputStream bos = null;try {String decodeUrl = UrlUtil.deCryptAndDecode(param);String fileName = decodeUrl.substring(decodeUrl.lastIndexOf("/") + 1);response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setContentType("application/x-msdownload");String filePath = request.getSession().getServletContext().getRealPath("") + decodeUrl;File file = new File(filePath);fis = new FileInputStream(file);bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(response.getOutputStream());int len = 0;byte[] bs = new byte[1024];while((len = bis.read(bs)) != -1){bos.write(bs, 0, len);}bos.flush();bos.close();} catch (Exception e) {logger.error("download file exception:",e);} finally {if (fis != null) {try {fis.close();} catch (IOException e) {logger.error("IO close exception:",e);}}if (bos != null) {try {bos.close();} catch (IOException e) {logger.error("IO close exception:",e);}}}} }常用的*.action或*.do的url對應的后臺處理:
package com.zy.web.controller;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;import com.zy.web.common.UrlUtil;@Controller public class DownloadController1{private static final Logger logger = LoggerFactory.getLogger(DownloadController1.class);@RequestMapping("/download1/test")public void downloadFile(HttpServletRequest request,HttpServletResponse response){InputStream fis = null;BufferedInputStream bis = null;BufferedOutputStream bos = null;try {String decodeUrl = UrlUtil.deCryptAndDecode(request.getParameter("url"));String fileName = decodeUrl.substring(decodeUrl.lastIndexOf("/") + 1);response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setContentType("application/x-msdownload");String filePath = request.getSession().getServletContext().getRealPath("") + decodeUrl;File file = new File(filePath);fis = new FileInputStream(file);bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(response.getOutputStream());int len = 0;byte[] bs = new byte[1024];while((len = bis.read(bs)) != -1){bos.write(bs, 0, len);}bos.flush();bos.close();} catch (Exception e) {logger.error("download file exception:",e);} finally {if (fis != null) {try {fis.close();} catch (IOException e) {logger.error("IO close exception:",e);}}if (bos != null) {try {bos.close();} catch (IOException e) {logger.error("IO close exception:",e);}}}} } 這樣就能讓瀏覽器正確地下載到項目里面希望用戶能夠下載的資源而避免安全隱患了。(同時解決下載文件名為中文亂碼問題)總結
以上是生活随笔為你收集整理的企业提供下载链接的安全解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: ruby语言+Devkit 工具
- 下一篇: UPX单步脱壳
