要说防盗链,得先说盗链。见名知义,盗链就是盗取别人的链接,最常见的就是盗图了。那么怎么防火防盗呢?传统的防盗链是通过http协议中的referer请求头来跟踪请求的来源,进而判断是否本站点的请求,从而达到防盗的目的。Referer长啥样?我用Fiddler抓了个包,看图
但目前更流行的防盗链方式是url签名,基本实现方案是针对请求参数签名,加入到url中,接收到该url后验证签名,通过则说明是自己人。参数的选取一般是个变量,比如时间戳、用户ID,签名算法一般是MD5。下面看个例子:
public void action(HttpServletRequest request, HttpServletResponse response) { String purl = RequestTool.getParameter(ParamKeys.purl); // 获取原来的加密串 String oldHash = RequestTool.getParameter(ParamKeys.safetyChainHashValue); // 获取session中保存的随机数 String rands = (String)RequestTool.getSession().getAttribute(AttributeKeys.RANDOM_NUM); String msisdn = UserSession.getUserID(request); // 防盗链加密并加上随机数 String hash = OrderHashTools.getSameUserHash(msisdn, rands); String newHash = SessionTools.encode(hash); // 防盗链校验通过,清空session中的随机数 RequestTool.getSession().removeAttribute(AttributeKeys.RANDOM_NUM); OptResultBean resultBean = new OptResultBean(); resultBean.setBackUrl(purl); // 如果防盗链不相等则跳通用的操作结果页 if (StringTools.isEmpty(oldHash) || StringTools.isEmpty(newHash) || !StringTools.isEq(oldHash, newHash)) { String sucMsg = PortalCacheManager.getParamValue("Anti_theft_chain_describe"); resultBean.setResultMsg(sucMsg); RequestTool.getSession().setAttribute(AttributeKeys.OPERATE_RESULT, resultBean); // 跳通用的操作结果页 String url = UrlTools.processForView(PreUrlConfig.getPreUrl(PreUrlConfig.OPERATE_RESULT_URL)); RequestTool.sendRedirectAppendParams(url); return; } // 领取提示语 String sucMsg = ""; // 结果码 String resultCode = ""; Response resp = ((IserverService)ContextRegistry.getContextHolder().getContext().getBean("WlfService")) .exchangeCode("", "", ""); if (Util.isNotEmpty(resp)) { resultCode = resp.getResultCode(); if (StringTools.isEq(resultCode, GET_KINDLE_SUCCESS)) { // 领取成功 sucMsg = resp.getPromptSuccess(); resultBean.setResultMsg(sucMsg); } else if (StringTools.isEq(resultCode, GET_KINDLE_FAIL)) { // 领取失败 sucMsg = resp.getPromptFailure(); resultBean.setResultMsg(sucMsg); } } RequestTool.getSession().setAttribute(AttributeKeys.OPERATE_RESULT, resultBean); // 跳通用的操作结果页 String url = UrlTools.processForView(PreUrlConfig.getPreUrl(PreUrlConfig.OPERATE_RESULT_URL)); RequestTool.sendRedirectAppendParams(url); return; }
看下加密算法:
/** * 根据手机号获得防盗链key加随机数 * @param msisdn 手机号 * @param random 随机数 * @return * @see [类、类#方法、类#成员] */ public static String getSameUserHash(String msisdn,String random) { StringBuffer sb = new StringBuffer(); sb.append(msisdn); sb.append(ENCRYPT_KEYS); sb.append(random); // 对字符串做MD5加密,再进行Base64编码 return ThreeDes.base64AndMd5(sb.toString()); }