网页上的一些事——拒绝“坏人”

来源:互联网 发布:2015手机淘宝最新版 编辑:程序博客网 时间:2024/04/30 20:12

  页防盗链

防盗链的概念:

  网页显示的内容不在自己服务器上,而通过技术手段,绕过别人放广告有利益的最终页,直接在自己的有广告有利益的页面上向最终用户提供此内容,这样没有任何资源的网站利用了别的网站的资源来展示给浏览者,提高了自己的访问量,而大部分浏览者又不会很容易地发现,这样显然,对于那个被利用了资源的网站是不公平的。

  盗链常见种类:图片盗链和文件盗链。

盗链防止办法:

  1、基于http协议头中的referer头字段,通过该字段可以知道引用网站的网址,而通过判断该引用网站是否合法便可以阻止盗链现象。

如:有这么个链接:

<a href="http://localhost:8080/fday06/servlet/DemoServlet">凤姐最新消息</a>

所链接到的网站的首页为:

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <title></title>
  </head>
 
  <body>
  广告。。。。。。。。。
    <a href="/fday06/servlet/DemoServlet">惊爆凤姐最新消息.................</a>
  </body>
</html>

接到的DemoServlet的内容:

package cn.itcast.request;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.
servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class DemoServlet extends HttpServlet {

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.getRequestDispatcher("/WEB-INF/Demo.jsp").forward(request, response);
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  this.doGet(request, response);
 }
}
时随便任何网站通过一个连接地址指向DemoServlet便可以盗走该网站的信息,而浏览者则毫不知情,要解决这个情况可将DemoServlet的doGet()方法修改为:

 String referer=request.getHeader("referer");
  //referer为null之浏览器通过地址直接访问,
  //referer不是
http://localhost则指为从别的网站链接而来
  //以上两种情况下均使页面跳转到本网站首页
  if(referer==null||!referer.startsWith("
http://localhost")){  
   response.sendRedirect("/fday06/index.jsp");
   return ;
  }
  request.getRequestDispatcher("/WEB-INF/Demo.jsp").forward(request, response);

2、通过自定义标签技术防盗链:

首页代码:

<html>
  <head>
  <title></title>
  </head>
 
  <body>
  广告。。。。。。。。。
    <a href="/fday11/example/DemoReferer.jsp">惊爆凤姐最新消息.................</a>
  </body>
</html>

 链接页面代码:

<%@ page language="java" pageEncoding="UTF-8"%>
<
%@taglib uri="http://www.exfrc.org" prefix="exfrc"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" >

//使用自定义处理防盗链标签
<exfrc:DemoReferer site="http://localhost" page="index.jsp" />  <html>
  <head>
    <title>DemoReferer</title>
  </head>
  <body>
  凤姐....................凤姐
  </body>
</html>

标签处理DemoReferer.java页面代码

package cn.itcast.web.example;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class DemoReferer extends SimpleTagSupport {
 private String site;
 private String page;

 public void setSite(String site) {
  this.site = site;
 }

 public void setPage(String page) {
  this.page = page;
 }

 @Override
 public void doTag() throws JspException, IOException {
  PageContext context=(PageContext) this.getJspContext();
  HttpServletRequest request=(HttpServletRequest) context.getRequest();
  HttpServletResponse response=(HttpServletResponse) context.getResponse();
  String referer=request.getHeader("referer");
  if(referer==null||!referer.startsWith(site)){   //必须先判null 否则可能出现空指针异常
   if(page.startsWith(request.getContextPath())){
    response.sendRedirect(page);
   }else if(page.startsWith("/")){
    response.sendRedirect(request.getContextPath()+page);
   }else{
    response.sendRedirect(request.getContextPath()+"/"+page);
   }
   throw new SkipPageException();
  }
 }
 
}
这两种方法本质上一样都是通过referer头字段进行防盗链,但是事实上这种防盗链是只能防君子而防不了小人的,也就是我们同样可以通过别的方法绕过服务器对referer的检查(如可以通过HttpURLConnection函数给链接地址发送假的referer头,从而绕过对referer的检查),所以这种防盗链防不死,天下没有不透风的墙,所以也没绝对完美的解决方案,貌似要想防死只能通过登录限制了...

表单防止重复提交

什么是表单的重复提交?

  前提:在控制器中页面的跳转形式为请求转发不是请求重定向;

重复提交的表现形式:

1、在页面未转到提交页面时,多次点击提交按钮;

2、成功提交后,多次点击刷新(F5)按钮;

3、成功提交后,后退,再次点击提交按钮;

防止表单重复提交的方案:

1、在客户端防止;2、在服务器端防止;

在客户端防止之一:

在提交按钮上利用JavaScript实现,点击一次后,将onclick置为false,表单页面如下:

 <head>
  <title>form.html</title>
  
  <script type="text/javascript">
   var iscommitted=false;
   function dosubmit(){
     if(!iscommitted){
      iscommitted=true;
      
      return true;
     }
     else{
        
      return false;
     }
   }
  </script>
 </head>

 <body>
  <form action="/fday07/servlet/formSubmitServlet1" method="post">
   用户:
   <input type="text" name="username">
   <br />
   密码:
   <input type="password" name="password">
   <br />
   <input type="submit" value="提交" onclick="return dosubmit()">
   <br />
  </form>
 </body>

客户端防止之二:

原理类似一都是利用JavaScript实现,但是是在提交按钮点击后将该按钮disabled属性置为disabled,表单页面代码如下:

 <head>
  <title>form.html</title>
  
  <script type="text/javascript">
   function dosubmit(){
    document.getElementById("submit").disabled='disabled';
    return true;
   }

  </script>
 </head>

 <body>
  <form action="/fday07/servlet/formSubmitServlet1" method="post">
   用户:
   <input type="text" name="username">
   <br />
   密码:
   <input type="password" name="password">
   <br />
   <input type="submit" value="提交" onclick="return dosubmit()">
   <br />
  </form>
 </body>

通过JavaScript防止客户端重复提交还是存在一定问题的,首先,客户端浏览器可能禁用JavaScript,其次防止不了提交成功后用户点击多次刷新按钮实现的重复提交,所以保险起见,在服务器端对表单重复提交的防止是很必须的!

首先客户端程序:

public class formServlet extends HttpServlet {

 private static final long serialVersionUID = 1L;

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  response.setCharacterEncoding("UTF-8");
  response.setContentType("text/html;charset=UTF-8");
  PrintWriter out = response.getWriter();
  String token=TokenProcessor.getInstance().generateToken();
  //request.setAttribute("token", token);
  request.getSession().setAttribute("token", token);              //服务器端的令牌
  out.print("<form action='formSubmitServlet' method='post'>");
  out.print("<input type='hidden' name='token' value='"+token+"'/>"); //客户端带过去的令牌
  out.print("<input type='text' name='username'/>");
  out.print("<input type='submit' value='提交'>");
  out.print("</form>");
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  this.doGet(request, response);
 }

}

class TokenProcessor {
 private TokenProcessor() {
 };

 public static final TokenProcessor instance = new TokenProcessor();

 public static TokenProcessor getInstance() {
  return instance;
 }

 public String generateToken() {
  String token = System.currentTimeMillis() + ""
    + new Random().nextInt(66666666);
  MessageDigest md;
  try {
   md = MessageDigest.getInstance("md5");
   byte md5[] = md.digest(token.getBytes());
   BASE64Encoder encoder = new BASE64Encoder();
   return encoder.encode(md5);
  } catch (NoSuchAlgorithmException e) {
   throw new RuntimeException(e);
  }
 }
}
服务器端程序:

public class formSubmitServlet extends HttpServlet {

 private static final long serialVersionUID = 1L;

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  boolean b=isToken(request);
  if(!b){
   System.out.println("重复提交!!");
   return ;
  }
  request.getSession().removeAttribute("token");  //比较完毕后服务器端移除令牌
  String username=request.getParameter("username");
  //out.write(username+"已经成功登录");
  System.out.println(username+"用户信息已经保存到数据库");
 }

 private boolean isToken(HttpServletRequest request) {
  String client_token=request.getParameter("token");
  if(client_token==null){
   return false;
  }
  String server_token=(String) request.getSession().getAttribute("token");
  if(server_token==null){
   return false;
  }
  if(!client_token.equals(server_token)){
   return false;
  }
  return true;
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  this.doGet(request, response);
 }

}
在服务器端防止表单重复提交的原理主要是,在客户端提交页面时生成一个唯一的token(用于唯一标识该用户)通过隐藏域带给服务器,该token为客户端client_token,同时将该token保存到request域中做为服务器端server_token,数据带到服务器端后,若为第一次提交则client_token=server_token,此时服务器端则移除保存在request域中的server_token。

如果此时用户点击刷新再次提交时,因为此时server_token==null所以再次提交也不会成功

如果用户不是通过表单提交页面链接到的该页面,那么因为server_token和client_token都为null,所以同样会阻止提交的发生。

原创粉丝点击