您的位置:首页 > 产品设计 > UI/UE

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

2012-12-10 14:45 716 查看
首先是web.xml

[html]
view plaincopyprint?

<?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> 

<?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

[html]
view plaincopyprint?

<%@ 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> 

<%@ 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

[java]
view plaincopyprint?

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); 
        } 
    } 


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

[java]
view plaincopyprint?

package com.jadyer.servlet; 

 
import java.io.IOException; 

 
import javax.servlet.ServletException; 

import javax.servlet.http.HttpServlet; 

import javax.servlet.http.HttpServletRequest; 

import javax.servlet.http.HttpServletResponse; 

 
public class FormServlet
extends HttpServlet { 
    private static
final long serialVersionUID = -3435386674549645942L; 

 
    public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { 

        /**
         * 利用referer防盗链

         * @see 客户端访问时,只认可以http://127.0.0.1为首的URL

         */ 
        String referer = request.getHeader("referer"); 

        if(null==referer || !referer.startsWith("http://127.0.0.1")){ 

            response.sendRedirect("/index.jsp"); 

            return;
//如果没有这行代码,那么重定向之后,下面的代码仍会执行 
        } 
         
        /**
         * 判断表单重复提交
         * @see 思路:详见我的另一篇文章http://blog.csdn.net/jadyer/article/details/6174095

         */ 
        if(!isTokenValid(request, response)){ 

            System.out.println("请不要重复提交表单..."); 

            return; 
        } 
        request.getSession().removeAttribute("myToken"); 

        System.out.println("向数据库中注册用户..."); 

    } 
     
    /**
     * 判断表单令牌是否有效
     */ 
    private boolean isTokenValid(HttpServletRequest request, HttpServletResponse response){ 

        String client_token = request.getParameter("myToken"); 

        String server_token = (String)request.getSession().getAttribute("myToken"); 

        if(null == client_token){ 

            return
false; 
        } 
        if(null == server_token){ 

            return false; 

        } 
        if(!client_token.equals(server_token)){ 

            return
false; 
        } 
        return true; 

    } 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐