Servlet处理表单重复提交and利用referer防盗链and实现request包含页面

首先是web.xml

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <web-app version="2.5" 
  3.     xmlns="http://java.sun.com/xml/ns/javaee" 
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 
  7.     <servlet> 
  8.         <servlet-name>FormServlet</servlet-name> 
  9.         <servlet-class>com.jadyer.servlet.FormServlet</servlet-class> 
  10.     </servlet> 
  11.     <servlet-mapping> 
  12.         <servlet-name>FormServlet</servlet-name> 
  13.         <url-pattern>/servlet/FormServlet</url-pattern> 
  14.     </servlet-mapping> 
  15.      
  16.     <welcome-file-list> 
  17.         <welcome-file>form.jsp</welcome-file> 
  18.     </welcome-file-list> 
  19. </web-app> 
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<servlet>
		<servlet-name>FormServlet</servlet-name>
		<servlet-class>com.jadyer.servlet.FormServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>FormServlet</servlet-name>
		<url-pattern>/servlet/FormServlet</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>form.jsp</welcome-file>
	</welcome-file-list>
</web-app>

然后是表单页面form.jsp

  1. <%@ page language="java" pageEncoding="UTF-8"%> 
  2. <%@ page import="com.jadyer.util.DataCoderUtil"%> 
  3. <
  4. //生成表单令牌 
  5. session.setAttribute("myToken", DataCoderUtil.generateToken()); 
  6. //request包含页面:也可以使用这种方式,把页面包含进来 
  7. //request.getRequestDispatcher("/form.jsp").include(request, response); 
  8. %> 
  9.  
  10. <form action="<%=request.getContextPath()%>/servlet/FormServlet" method="POST"> 
  11.     <input type="hidden" name="myToken" value="${myToken}"> 
  12.     用户:<input type="text" name="username"><br/> 
  13.     密码:<input type="password" name="password"><br/> 
  14.     <input type="submit" value="提交"> 
  15. </form> 
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page import="com.jadyer.util.DataCoderUtil"%>
<%
//生成表单令牌
session.setAttribute("myToken", DataCoderUtil.generateToken());
//request包含页面:也可以使用这种方式,把页面包含进来
//request.getRequestDispatcher("/form.jsp").include(request, response);
%>

<form action="<%=request.getContextPath()%>/servlet/FormServlet" method="POST">
	<input type="hidden" name="myToken" value="${myToken}">
	用户:<input type="text" name="username"><br/>
	密码:<input type="password" name="password"><br/>
	<input type="submit" value="提交">
</form>

下面是用于生成表单令牌的工具类DataCoderUtil.java

  1. package com.jadyer.util; 
  2.  
  3. import java.security.MessageDigest; 
  4. import java.security.NoSuchAlgorithmException; 
  5. import java.util.Random; 
  6.  
  7. import sun.misc.BASE64Encoder; 
  8.  
  9. /**
  10. * DataCoderUtil
  11. * @see ========================================================================================
  12. * @see 这里的generateToken()是处理表单重复提交时,创建的表单令牌生成器,其返回经MD5和base64加密后的String
  13. * @see ========================================================================================
  14. * @see Java中每个数据都有一个摘要,即数据指纹。无论这个数据有多大,它的指纹都是固定的128位,即16个字节
  15. * @see 我们可以使用Java中提供的java.security.MessageDigest工具类,得到随机数的数据摘要,即数据指纹
  16. * @see ========================================================================================
  17. * @see 全新算法:base64编码
  18. * @see 任何数据经base64算法编码后,都会返回明文的字符串。该算法有一个特点:它会把每三个字节,都变成四个字节
  19. * @see 比如00110010.11001101.00101001会被变成00001100.00101100.00110100.00101001
  20. * @see 也就是把原来的24Bit平均分为四份,然后在每一份前面补两个零,以此凑成32Bit,即四个字节
  21. * @see 故,改变之后的四个字节,每个字节的最小值就是00000000,最大值就是00111111,即最小为零,最大为63
  22. * @see 所以,经过base64算法编码后,每个字节的最大值都不会超过64
  23. * @see 最后,base64算法会查询它自己定制的码表,该码表记录的是0--63所对应键盘上的明文字符,最后将其返回
  24. * @see ========================================================================================
  25. * @author 宏宇
  26. * @create Mar 6, 2012 2:38:04 AM
  27. */ 
  28. public class DataCoderUtil { 
  29.     public static String generateToken() { 
  30.         String myToken = System.currentTimeMillis() + new Random().nextInt() + ""
  31.         try
  32.             byte[] myTokenMD5 = MessageDigest.getInstance("md5").digest(myToken.getBytes()); //MD5算法加密 
  33.             return new BASE64Encoder().encode(myTokenMD5); //base64算法加密,最后返回 
  34.         } catch (NoSuchAlgorithmException e) { 
  35.             throw new RuntimeException(e); 
  36.         } 
  37.     } 
package com.jadyer.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import sun.misc.BASE64Encoder;

/**
 * DataCoderUtil
 * @see ========================================================================================
 * @see 这里的generateToken()是处理表单重复提交时,创建的表单令牌生成器,其返回经MD5和base64加密后的String
 * @see ========================================================================================
 * @see Java中每个数据都有一个摘要,即数据指纹。无论这个数据有多大,它的指纹都是固定的128位,即16个字节
 * @see 我们可以使用Java中提供的java.security.MessageDigest工具类,得到随机数的数据摘要,即数据指纹
 * @see ========================================================================================
 * @see 全新算法:base64编码
 * @see 任何数据经base64算法编码后,都会返回明文的字符串。该算法有一个特点:它会把每三个字节,都变成四个字节
 * @see 比如00110010.11001101.00101001会被变成00001100.00101100.00110100.00101001
 * @see 也就是把原来的24Bit平均分为四份,然后在每一份前面补两个零,以此凑成32Bit,即四个字节
 * @see 故,改变之后的四个字节,每个字节的最小值就是00000000,最大值就是00111111,即最小为零,最大为63
 * @see 所以,经过base64算法编码后,每个字节的最大值都不会超过64
 * @see 最后,base64算法会查询它自己定制的码表,该码表记录的是0--63所对应键盘上的明文字符,最后将其返回
 * @see ========================================================================================
 * @author 宏宇
 * @create Mar 6, 2012 2:38:04 AM
 */
public class DataCoderUtil {
	public static String generateToken() {
		String myToken = System.currentTimeMillis() + new Random().nextInt() + "";
		try {
			byte[] myTokenMD5 = MessageDigest.getInstance("md5").digest(myToken.getBytes()); //MD5算法加密
			return new BASE64Encoder().encode(myTokenMD5); //base64算法加密,最后返回
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
}

最后是用于处理表单请求的FormServlet.java

  1. package com.jadyer.servlet; 
  2.  
  3. import java.io.IOException; 
  4.  
  5. import javax.servlet.ServletException; 
  6. import javax.servlet.http.HttpServlet; 
  7. import javax.servlet.http.HttpServletRequest; 
  8. import javax.servlet.http.HttpServletResponse; 
  9.  
  10. public class FormServlet extends HttpServlet { 
  11.     private static final long serialVersionUID = -3435386674549645942L; 
  12.  
  13.     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  14.         /**
  15.          * 利用referer防盗链
  16.          * @see 客户端访问时,只认可以http://127.0.0.1为首的URL
  17.          */ 
  18.         String referer = request.getHeader("referer"); 
  19.         if(null==referer || !referer.startsWith("http://127.0.0.1")){ 
  20.             response.sendRedirect("/index.jsp"); 
  21.             return; //如果没有这行代码,那么重定向之后,下面的代码仍会执行 
  22.         } 
  23.          
  24.         /**
  25.          * 判断表单重复提交
  26.          * @see 思路:详见我的另一篇文章http://blog.csdn.net/jadyer/article/details/6174095
  27.          */ 
  28.         if(!isTokenValid(request, response)){ 
  29.             System.out.println("请不要重复提交表单..."); 
  30.             return
  31.         } 
  32.         request.getSession().removeAttribute("myToken"); 
  33.         System.out.println("向数据库中注册用户..."); 
  34.     } 
  35.      
  36.     /**
  37.      * 判断表单令牌是否有效
  38.      */ 
  39.     private boolean isTokenValid(HttpServletRequest request, HttpServletResponse response){ 
  40.         String client_token = request.getParameter("myToken"); 
  41.         String server_token = (String)request.getSession().getAttribute("myToken"); 
  42.         if(null == client_token){ 
  43.             return false
  44.         } 
  45.         if(null == server_token){ 
  46.             return false
  47.         } 
  48.         if(!client_token.equals(server_token)){ 
  49.             return false
  50.         } 
  51.         return true
  52.     } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值