文章目录
  1. 1. 防止浏览器缓存(304)
  2. 2. 防止重复提交
    1. 2.1. 实例代码
      1. 2.1.1. index.jsp
      2. 2.1.2. Test.java(是一个Servlet)
  3. 3. 防止请求伪造

今天在项目中碰到了时间戳,类似这样的格式yyyyMMddHHmmss,本文就时间戳进行一个简短的总结。

防止浏览器缓存(304)

URL 的末尾追加了时间。这就确保了请求不会在它第一次被发送后即缓存,而是会在此方法每次被调用后重新创建和重发;
此 URL 会由于时间戳的不同而稍微有些不同。

这种技巧常被用于确保到脚本的 POST 每次都会实际生成新请求且 Web 服务器不会尝试缓存来自服务器的响应。

防止重复提交

每次请求时产生一个token(一般为时间戳),存于session中并随之用hidden提交,
在服务端中判断接收到的token和session中的是否一致来判断是否重复提交,
如果不是则重新产生一个 token存于session中覆盖原来的token。

实例代码

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
<%  
    String path = request.getContextPath();  
    String basePath = request.getScheme() + "://"  
            + request.getServerName() + ":" + request.getServerPort()  
            + path + "/";  
%>  

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>  
<head>  
<base href="<%=basePath%>">  

<title>My JSP 'index.jsp' starting page</title>  
<meta http-equiv="pragma" content="no-cache">  
<meta http-equiv="cache-control" content="no-cache">  
<meta http-equiv="expires" content="0">  
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
<meta http-equiv="description" content="This is my page">  
<!-- 
    <link rel="stylesheet" type="text/css" href="styles.css"> 
    -->  
</head>  

<body>  
    <%  
        long token = System.currentTimeMillis(); //产生时间戳的token  
        session.setAttribute("token", token);  
    %>  
    <form action="Test" method="post">  
        <input type="text" name="username" /> <input type="text"  
            name="password" /> <input type="hidden" value="<%=token%>"  
            name="token" />  
        <!-- 作为hidden提交 -->  
        <input type="submit" value="提交" />  
    </form>  
</body>  
</html>  

Test.java(是一个Servlet)

public class Test extends HttpServlet {  
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
throws ServletException, IOException {  


        this.doPost(request, response);  
    }  
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
        throws ServletException, IOException {  
        req.setCharacterEncoding("utf-8");  
        resp.setCharacterEncoding("utf-8");  
        resp.setContentType("text/html,charset=utf-8");  
        String username = req.getParameter("username");  
        String password = req.getParameter("password");  
        long token = Long.parseLong(req.getParameter("token"));  
        long tokenInSession = Long.parseLong(req.getSession().getAttribute(  
        "token")  
        + "");  
        if (token == tokenInSession) {  
            resp.getWriter().println("ok ");  
            // 如果是第一次请求,则产生新的token,以防止下次的重复的提交  
            req.getSession().setAttribute("token", System.currentTimeMillis());  
        } else {  
            resp.getWriter().println("do not repeat submit");  
        }  
    }  
}  

@当用户返回或者刷新重复请求服务端时,服务端判断token是否一致,
由于请求方没有产生新的token,所以和服务端新产生的token不一致,认为重复提交。

@当用户在请求页面刷新也就是重新在请求页面产生token,这时新的token覆盖服务端产生的token,
这时token一致,认为是一个新的请求。

防止请求伪造

如过客户端在向服务端接口进行请求,如果请求信息进行了加密处理,被第三方截取到请求包,
虽然第三方无法解密获取其中的数据,但是可以使用该请求包进行重复的请求操作。
如果服务端不进行防重放攻击,就会参数服务器压力增大,数据紊乱的后果。
而使用添加时间戳的方式可以解决这一问题。

每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数一起进行数字签名。因为一次正常的HTTP请求,从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间相比较,是否超过了60s,如果超过了则认为是非法的请求。

假如黑客通过抓包得到了我们的请求url:

http://xxx.site/index/Info?uid=ZX07&stime=1480862753&sign=80b886d71449cb33355d017893720666 

其中

sign=md5(uid,token,stime);
// token是MD5散列的一个要素,一般保密

一般情况下,黑客从抓包重放请求耗时远远超过了60s,所以此时请求中的stime参数已经失效了。
如果黑客修改stime参数为当前的时间戳,则sign参数对应的数字签名就会失效,因为黑客不知道token值,没有办法生成新的数字签名。

更多关于重放攻击的内容请参考百度百科的解释“重放攻击-百度百科”

文章目录
  1. 1. 防止浏览器缓存(304)
  2. 2. 防止重复提交
    1. 2.1. 实例代码
      1. 2.1.1. index.jsp
      2. 2.1.2. Test.java(是一个Servlet)
  3. 3. 防止请求伪造
Fork me on GitHub