月度归档:2020年02月

Windows平台下搭建自己的Git服务器

该文章转自:http://www.codeceo.com/article/windows-git-server.html

Gitblit 是一个纯 Java 库用来管理、查看和处理 Git 资料库,相当于 Git 的 Java 管理工具。

Gitblit 支持Linux操作系统,因此 Gitblit 需要java运行环境(JRE)。

如果公司要搭建自己的 Git 服务器,可以使用 Gitblit 这个开源的 Git 服务器。

第一步:下载Java

第二步:安装JDK步骤不再详述,网上教程一搜一大把,可参考:http://www.cnblogs.com/android-joker/p/4513125.html

第三步:确保电脑安装了Java 运行时环境 JRE 或者 JDK ( version >=1.7 )。

在命令窗口中,输入java命令:java -version,回车,如果出现版本信息,说明安装成功。

第四步:下载安装Gitblit

  1)下载Gitblit,下载地址:http://www.gitblit.com/

  2)解压缩下载的压缩包即可,无需安装

第五步:配置Gitblit

  1)创建用于存储资料的文件夹。

  2)找到Git目录下的data文件下的 gitblit.properties 文件,用“记事本”或文本编辑器打开。

3)找到 git.repositoriesFolder(资料库路径),赋值为  第1)步 创建好的文件目录。

4)找到 server.httpPort,设定http协议的端口号(注意:所使用的端口不要与已有端口冲突)。

5)找到 server.httpBindInterface,设定服务器的IP地址。这里就设定你的服务器IP。

  6)保存,关闭文件。

 

第六步:运行gitblit.cmd 批处理文件。

  1)找到 gitblit 目录中的 gitblit.cmd 文件,双击运行。

运行成功,结果如下:

  3)在浏览器中打开,现在就可以使用GitBlit了。

第七步:设置成服务方式(Windows Service)启动Gitblit

  1)在Gitblit目录下,找到 installService.cmd 文件。

  2)用“记事本”或文本编辑器打开。

  修改 ARCH

    32位系统:SET ARCH=x86

    64位系统:SET ARCH=amd64

  添加 CD 为程序目录

    SET CD=E:\Git\gitblit-1.8.0 (你的实际目录)

  修改StartParams里的启动参数

    给空就可以了

  3)保存,关闭文件。

  4)关闭正在运行的cmd命令窗口,以管理员身份运行Gitblit目录下的installService.cmd文件。

  5)在服务器运行窗口中键入“services.msc”回车,打开 Windows 服务窗口。

在服务中,就能看到已经存在的gitblit服务了

  6)启动该服务。平时使用时,保持这个服务是启动状态就可以了。

以上就是Windows平台下,配置 Gitblit服务器的全部的全部内容。

HttpSessionBindingListener接口讲解

实时在线人数统计方面的实现,上网找了下这方面的知识,最初我的想法是,管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退出,如:未注销,关闭浏览器等,这个用户的session是管理不到的,最后决定用HttpSessionListener接口或HttpSessionBindingListener接口来实现,通过监听session的新建和销毁来控制,详细如下。(讲解:HttpSessionListener和HttpSessionBindingListener接口的作用都是用来对session做监听的,一旦session有变就立马执行接口里面的方法

先添加登陆的页面index.jsp

<%@ page contentType="text/html;charset=utf-8"%>
<html>
<head>
<title>test</title>              
</head>
<body>
<form action="login.jsp" method="post">
    用户名:<input type="text" name="username" />
    <br />
    <input type="submit" value="登录" />
</form>
</body>
</html>

点击登陆后跳转的login.jsp(为了方便,用jsp做servlet,同学们用的时候记得改过来)

<%@ page contentType="text/html;charset=utf-8"%>
<%@ page import="java.util.*"%>
<%
    request.setCharacterEncoding("UTF-8");
    // 取得登录的用户名
    String username = request.getParameter("username");
    // 把用户名保存进session
    session.setAttribute("username", username);
    // 把用户名放入在线列表
    List onlineUserList = (List) application.getAttribute("onlineUserList");
    // 第一次使用前,需要初始化
    if (onlineUserList == null) {
        onlineUserList = new ArrayList();
        application.setAttribute("onlineUserList", onlineUserList);
    }
    onlineUserList.add(username);
    // 成功
    response.sendRedirect("result.jsp");
%>

登陆成功跳转到显示页面result.jsp

<%@ page contentType="text/html;charset=utf-8"%>
<%@ page isELIgnored="false"%>
<%@page import="java.util.List"%>
<h3>您好:${username} [<a href="logout.jsp">注销</a>]</h3>
当前在线用户:
<table>
<%
    List onlineUserList = (List) application.getAttribute("onlineUserList");
    for (int i = 0; i < onlineUserList.size(); i++) {
    String onlineUsername = (String) onlineUserList.get(i);
%>
    <tr>
        <td><%=onlineUsername%></td>
    </tr>
<%
}
%>
</table>

点击注销页面logout.jsp页面

<%@ page contentType="text/html;charset=utf-8"%>
<%@ page import="java.util.*"%>
<%
    // 取得登录的用户名
    String username = (String) session.getAttribute("username");
    // 销毁session
    session.invalidate();
    // 从在线列表中删除用户名
    List onlineUserList = (List) application.getAttribute("onlineUserList");
    onlineUserList.remove(username);
    // 成功
    response.sendRedirect("index.jsp");
%> 

OK,登陆、查看、注销页面都有了,下面开始新建监听器

1、HttpSessionListener

自定义一个类OnlineUserListener,继承HttpSessionListener,HttpSessionListener中有两个方法sessionCreated(HttpSessionEvent event)与sessionDestroyed(HttpSessionEvent event),前者是监听session的新建,后者是监听session的销毁。(讲解:从服务器后端做全局监听,只要有session创建,那就执行sessionCreated(HttpSessionEvent event)这个方法,只要有session销毁,那就执行sessionDestroyed(HttpSessionEvent event)方法

OnlineUserListener代码如下:

package com.test;
 
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
 * @author 版本
 */
public class OnlineUserListener implements HttpSessionListener {
 
	public void sessionCreated(HttpSessionEvent event) {
		System.out.println("新建session:"+event.getSession().getId());
	}
	public void sessionDestroyed(HttpSessionEvent event) {
		HttpSession session = event.getSession();
        ServletContext application = session.getServletContext();
        // 取得登录的用户名
        String username = (String) session.getAttribute("username");
        // 从在线列表中删除用户名
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        onlineUserList.remove(username);
        System.out.println(username+"已经退出!");
	}
}

web.xml配置:

<listener>
  <listener-class>com.test.OnlineUserListener</listener-class>
</listener>

一旦监听器发现某个session被关闭了,就会立马调用了sessionDestoryed方法(解释:在上面的代码里面我们在sessionDestroyed方法里面写的业务是把其用户从在线人数中delete),在下面两种情况下会发生sessionDestoryed事件

  1. 执行session.invalidate()方法时
    logout.jsp中调用了 session.invalidate()方法
  2. session会话超时
    session的默认超时事件是30分钟,30分钟后自动销毁session

2、HttpSessionBindingListener

HttpSessionBindingListener虽然叫做监听器,但使用方法与HttpSessionListener完全不同。我们实际看一下它是如何使用的。

我们先自定义一个OnlineUserBindingListener类,实现HttpSessionBindingListener接口,构造方法传入username参数,HttpSessionBindingListener内有两个方法valueBound(HttpSessionBindingEvent event)和valueUnbound(HttpSessionBindingEvent event),
前者为数据绑定(解释:所谓对session进行数据绑定,就是调用session.setAttribute()把HttpSessionBindingListener保存进session中。),

后者为取消绑定(解释
valueUnbound的触发条件是以下三种情况:
1. 执行session.invalidate()时。
2. session超时,自动销毁时。
3. 执行session.setAttribute(“onlineUserListener”, “其他对象”);或session.removeAttribute(“onlineUserListener”);将listener从session中删除时。
因此,只要不将listener从session中删除,就可以监听到session的销毁。)。

在login.jsp中做这一步:

<%@page import="com.test.OnlineUserBindingListener"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%@ page import="java.util.*"%>
<%
    request.setCharacterEncoding("UTF-8");
    // 取得登录的用户名
    String username = request.getParameter("username");
       // 把用户名放入在线列表     把我们自定义的OnlineUserBindingListener类实例化以后存到session里面去,只要这行代码一旦执行,那么就会触发OnlineUserBindingListener类里的valueBound(HttpSessionBindingEvent event)方法
    session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));
    // 成功
    response.sendRedirect("result.jsp");
%>

这就是HttpSessionBindingListener和HttpSessionListener之间的最大区别:HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。HttpSessionBindingListener必须实例化后放入某一个session中解释:例如 session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));把我们自定义的监听类存储到session中,这个监听器就像“寄生虫”一样赋于该session上),才可以进行监听。

从监听范围上比较,HttpSessionListener设置一次就可以监听所有session,HttpSessionBindingListener通常都是一对一的。

正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。

HttpSessionBindingListener代码如下:
(提示:在代码后面会有详细的代码讲解)

package com.test;
 
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
 
public class OnlineUserBindingListener implements HttpSessionBindingListener {
	String username;
	
	public OnlineUserBindingListener(String username){
		this.username=username;
	}
	public void valueBound(HttpSessionBindingEvent event) {
		HttpSession session = event.getSession();
	    ServletContext application = session.getServletContext();
	    // 把用户名放入在线列表
	    List onlineUserList = (List) application.getAttribute("onlineUserList");
	    // 第一次使用前,需要初始化
	    if (onlineUserList == null) {
	        onlineUserList = new ArrayList();
	        application.setAttribute("onlineUserList", onlineUserList);
	    }
	    onlineUserList.add(this.username);
	}
 
	public void valueUnbound(HttpSessionBindingEvent event) {
		HttpSession session = event.getSession();
	    ServletContext application = session.getServletContext();
 
	    // 从在线列表中删除用户名
	    List onlineUserList = (List) application.getAttribute("onlineUserList");
	    onlineUserList.remove(this.username);
	    System.out.println(this.username + "退出。");
 
	}
 
}

这里可以直接使用listener的username操作在线列表,不必再去担心session中是否存在username。

valueUnbound的触发条件是以下三种情况:

  1. 执行session.invalidate()时。
  2. session超时,自动销毁时。
  3. 执行session.setAttribute(“onlineUserListener”, “其他对象”);或session.removeAttribute(“onlineUserListener”);将listener从session中删除时。

因此,只要不将listener从session中删除,就可以监听到session的销毁。

来源:https://blog.csdn.net/qq_40241957/article/details/97906977

-------------

HttpSessionListener与HttpSessionBindingListener之间区别

1. 使用HttpSessionListener 编写一个OnlineUserListener。

Java代码
  1. package test;
  2. import java.util.List;
  3. import javax.servlet.ServletContext;
  4. import javax.servlet.http.HttpSession;
  5. import javax.servlet.http.HttpSessionListener;
  6. import javax.servlet.http.HttpSessionEvent;
  7. public class OnlineUserListener implements HttpSessionListener{
  8.     public void sessionCreated(HttpSessionEvent event) {}
  9.     public void sessionDestroyed(HttpSessionEvent event) {
  10.         HttpSession session = event.getSession();
  11.         ServletContext application = session.getServletContext();// 取得登录的用户名
  12.         String username = (String) session.getAttribute("username");// 从在线列表中删除用户名
  13.         List onlineUserList = (List) application.getAttribut("onlineUserList");
  14.         onlineUserList.remove(username);
  15.         System.out.println(username + "超时退出。");
  16.     }
  17. }

 

 

OnlineUserListener实现了HttpSessionListener定义的两个方法:sessionCreated()和 sessionDestroyed()。

这两个方法可以监听到当前应用中session的创建和销毁情况。我们这里只用到 sessionDestroyed()在session销毁

时进行操作就可以。

 

从HttpSessionEvent中获得即将销毁的session,得到session中的用户名,并从在线列表中删除。最后一句向

console打印一条信息,提示操作成功,这只是为了调试用,正常运行时删除即可。

 

为了让监听器发挥作用,我们将它添加到web.xml中:

 

<listener>

<listener-class>anni.OnlineUserListener</listener-class>

</listener>

 

 

以下两种情况下就会发生sessionDestoryed(会话销毁)事件:

 

执行session.invalidate()方法时。

 

既然LogoutServlet.java中执行session.invalidate()时,会触发sessionDestory()从在线用户列表中清除当前用户,我

们就不必在LogoutServlet.java中对在线列表进行操作了,所以LogoutServlet.java的内容现在是这样。

Java代码  收藏代码
  1. public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {    // 销毁session    
  2.     request.getSession().invalidate();    // 成功
  3.     response.sendRedirect("index.jsp");
  4. }

 

如果用户长时间没有访问服务器,超过了会话最大超时时间,服务器就会自动销毁超时的session。

会话超时时间可以在web.xml中进行设置,为了容易看到超时效果,我们将超时时间设置为最小值。

 

<session-config>

<session-timeout>1</session-timeout>

</session-config>

 

时间单位是一分钟,并且只能是整数,如果是零或负数,那么会话就永远不会超时。

 

为了验证OnlineUserListener是否能正常执行,我们可以登录两个用户,其中一个点击注销,另一个等待一分钟,然后可

以在console中看到输出的信息。

 

2. 使用HttpSessionBindingListener

HttpSessionBindingListener虽然叫做监听器,但使用方法与HttpSessionListener完全不同。我们实际看一下它是如何使用的。

 

我们的OnlineUserBindingListener实现了HttpSessionBindingListener接口,接口中共定义了两个方法:

valueBound()和valueUnbound(),分别对应数据绑定,和取消绑定两个事件。

 

所谓对session进行数据绑定,就是调用session.setAttribute()把 HttpSessionBindingListener保存进session中。

我们在LoginServlet.java中进行这一步。

 

// 把用户名放入在线列表

session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));

就是HttpSessionBindingListener和 HttpSessionListener之间的最大区别:

HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。

HttpSessionBindingListener必须实例化后放入某一个session中,才可以进行监听。

 

从监听范围上比较,HttpSessionListener设置一次就可以监听所有 session,

HttpSessionBindingListener通常都是一对一的。

 

正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,

这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。

 

valueBound()方法的代码如下:

Java代码  收藏代码
  1. public void valueBound(HttpSessionBindingEvent event) {
  2.     HttpSession session = event.getSession();
  3.     ServletContext application = session.getServletContext();
  4.     // 把用户名放入在线列表
  5.     List onlineUserList = (List) application.getAttribute("onlineUserList");// 第一次使用前,需要初始化
  6.     if (onlineUserList == null) {
  7.         onlineUserList = new ArrayList();
  8.         application.setAttribute("onlineUserList", onlineUserList);
  9.     }
  10.     onlineUserList.add(this.username);
  11. }

 

username已经通过构造方法传递给listener,在数据绑定时,可以直接把它放入用户列表。

 

与之对应的valueUnbound()方法,代码如下:

Java代码  收藏代码
  1. public void valueUnbound(HttpSessionBindingEvent event) {
  2.     HttpSession session = event.getSession();
  3.     ServletContext application = session.getServletContext();// 从在线列表中删除用户名
  4.     List onlineUserList = (List) application.getAttribute("onlineUserList");
  5.     onlineUserList.remove(this.username);
  6.     System.out.println(this.username + "退出。");
  7. }

 

这里可以直接使用listener的username操作在线列表,不必再去担心session中是否存在username。

 

valueUnbound的触发条件是以下三种情况:

 

执行session.invalidate()时。

 

session超时,自动销毁时。

 

执行session.setAttribute("onlineUserListener", "其他对象");

或session.removeAttribute("onlineUserListener");将listener从session 中删除时。

因此,只要不将listener从session中删除,就可以监听到session的销毁。

来源: https://www.iteye.com/blog/hy2012-2207902

Session管理之超时设置和强制下线

关于Session,在Java Web开发中,为我们提供了很多方便,Session是由浏览器和服务器之间维护的。好吧,闲话不多说,下面让我们一步一步来实现它们。

(一)首先来说下Session超时时间设置的三种方式,这些相对来说比较简单:

(1)在web.xml中设置session-config

 <session-config>

  <session-timeout>2</session-timeout>
 </session-config>

即交互间隔时间最长为2分钟(该处时间单位为分钟),2分钟后session.getAttribute()获取的值为空。

(2)在Tomcat的/conf/web.xml中session-config,默认值为:30分钟

<session-config>
     <session-timeout>30</session-timeout>
</session-config>

同上,时间单位为分钟。

(3)在Servlet中设置

HttpSession session = request.getSession();
session.setMaxInactiveInterval(60);

即在你的程序代码中手动设置(该处时间单位为秒)。

优先级:Servlet中设置 >web.xml设置 > Tomcat/conf/web.xml设置

(二)同一用户强制下线

大家都知道在目前很多的web项目中,大多数情况下都是可以让同一个用户账号在不同的登录入口登录的,但这样其实就显得不是很严谨了,毕竟信息修改等操作对于信息是否能完全即时同步还是个未知之数。所以,接下来,我要做的只是对于不同浏览器的同一个用户账号的强制下线处理,对于同一个浏览器暂不做考虑,先来看下面这张图。大概的了解一下:

aaaaq

从上面可以看出:同一个浏览器对于不同的账号,登录时会产生相同的sessionId,这也就导致了用户之间信息的覆盖;不同浏览器对于不同的账号登录时,登录时会产生不同的sessionId,这也就给了我们可操作的空间了,正是要利用这一点来进行判断和相应处理。

(1)添加监听器

为了方便这里使用Session监控的方式,创建SessionListener,如下:

public class SessionListener implements HttpSessionBindingListener{

    @Override
    public void valueBound(HttpSessionBindingEvent event){
        // TODO Auto-generated method stub

    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event){
        // TODO Auto-generated method stub

    }
}

这里HttpSessionBindingListener和HttpSessionListener效果一样,大家可以任选其一。重载两个方法:session的创建和销毁。

当然,在web.xml中添加相应配置是必不可少的:

<listener>
   <listener-class>com.yoki.util.SessionListener</listener-class>
</listener>

由于sessionId和userId需要存储,方便后面的判断,我们在上面的类中添加两个Map,如下:

//保存username和session的映射
public static HashMap<String,Session> MAP1 = new HashMap<String,Session>();
//保存sessionID和username的映射
public static HashMap MAP2 = new HashMap();

最后,用户登录验证成功时需要调用一个方法来判断是否强制下线:

public static void userLogin(Session session,String sUserName){
    //已登录
    if(MAP2.containsValue(sUserName)){
       Session l_session = MAP1.get(sUserName);
       //不同浏览器,同一用户(强制下线前一个)
       if(l_session != null && l_session.getId() != session.getId()){
          MAP1.remove(sUserName);
          MAP2.remove(l_session.getId());
          l_session.setAttribute("msg", "您的账号已在另一处登录!");
          MAP2.put(session.getId(), sUserName);
          MAP1.put(sUserName, session);
       }
       //同一浏览器,同一用户(不做任何变动)

    }else{
       //未登录
       if(MAP2.containsKey(session.getId())){
          //同一浏览器,不同用户(不做任何变动)
       }else{
          //不同浏览器,不同用户(正常添加)
          MAP2.put(session.getId(), sUserName);
          MAP1.put(sUserName, session);
       }
    }

}

解释一下:这里使用username和userId效果一样,看你们怎么方便怎么用了,方法中的逻辑是根据上面的图来编写的,首先判断用户是否登录了,因为MAP中保存了相关的session关联信息,所以可以通过这个来判断;由于此处只对不同浏览器相同用户进行处理,所以直接判断是否是同一个浏览器。方法的参数session是用户在当前浏览器登录时的信息,我们可以从MAP中得到之前保存过的相同用户的session信息,与之进行比较,里面的逻辑是:移除MAP中保存的之前的用户信息(对应的session此时未销毁),并给其session添加一个msg信息(后面用到,往下看),再添加新的用户信息。

上面的方法调用放在登录验证成功后,各自项目不同,但登录验证的类基本差不多:

SessionListener.userLogin(session, USERNAME);

(2)添加前端页面调用的方法

在登录验证的类中添加如下方法:

/*
 * 判断用户是否重复登录
 */
@RequestMapping(value="/checkUserOnline")
@ResponseBody
public void checkUserOnline(HttpServletRequest request,HttpServletResponse response) throws IOException{
    HttpSession session=request.getSession();  
    PrintWriter out = response.getWriter();
    String msg = "";
    if(session.getAttribute("msg") != null){
       msg = session.getAttribute("msg").toString();
       System.out.println(msg);
    }
    out.print(session.getAttribute("msg"));
}

方法中获取之前添加到session中的msg,用来判断是否强制下线,继续。

(3)前端页面循环调用

选择一个页面,最好是所有页面都用到的,比如我用的index.jsp,如下:

<script type="text/javascript">
   $(document).ready(function(){
      setInterval("checkUserOnline()",5000); //每隔5秒判断一次
   }

   function checkUserOnline(){
      var msg = "";
      $.ajax({
        type : "POST",
        url : "checkUserOnline",
        data : {},
        async: false,
        success : function(data){
           msg = data;
        }
      });
      if (msg == 'null' || msg == '' || msg == 'undefined'){
         return;
      }else{
         //调用你的注销用户方法
         var url="<%=path%>/logout.do";
         $.get(url,function(data){});
      }
   }
</script>

js中调用setInterval方法,设置调用的方法和间隔时间,方法里通过ajax调用上面添加的类并返回msg,通过msg来判断是否调用注销方法(路径啥的自己注意,能调用到就ok)。

(4)注销

一般web项目登录进去后都会有个退出按钮,点击即返回到登录页,此时在里面添加一行代码,防止错误,可能会出现重新登录报session已被销毁的错误提示,但第二次便会成功,这里便是为了消除该错误:

SessionListener.MAP2.remove(session.getId());

好了,基本的设置完成了,启动项目,打开两个不同的浏览器,先登录一个用户,成功后,在另一个浏览器中登录相同的用户,登录成功后,会在控制台上打印出msg:

您的账号已在另一处登录!

此时,刷新第一个浏览器用户登录界面,便会发现已经退出跳转到登录页了,大功告成!!!

 

来源:   https://www.jianshu.com/p/9a3078d0081b

 

XSS简单理解之AntiSamy

AntiSamy介绍

OWASP是一个开源的、非盈利的全球性安全组织,致力于应用软件的安全研究。我们的使命是使应用软件更加安全,使企业和组织能够对应用安全风险作出更清晰的决策。目前OWASP全球拥有140个分会近四万名会员,共同推动了安全标准、安全测试工具、安全指导手册等应用安全技术的发展。

OWASP AntiSamy项目可以有好几种定义。从技术角度看,它是一个可确保用户输入的HTML/CSS符合应用规范的API。也可以这么说,它是个确保用户无法在HTML中提交恶意代码的API,而这些恶意代码通常被输入到个人资料、评论等会被服务端存储的数据中。在Web应用程序中,“恶意代码”通常是指 Javascript。同时层叠样式表(CSS)在调用Javascript引擎的时候也会被认为是恶意代码。当然在很多情况下,一些“正常”的HTML 和CSS也会被用于恶意的目的,所以我们也会对此予以处理。

 

AnitiSamy下载

官方网站:https://www.owasp.org/index.php/Category:OWASP_AntiSamy_Project

项目地址:https://code.google.com/p/owaspantisamy/downloads/list

我们看到Downloads,下载WhereToGet.txt就可以看到下载地址

 

标准策略文件说明

antisamy-slashdot.xml

Slashdot (  http://www.slashdot.org/  )  是一个提供技术新闻的网站,它允许用户用有限  的  HTML  格式的内容匿名回帖。  Slashdot 不仅仅是目前同类中最酷的网站之一,而  且同时也曾是最容易被成功攻击的网站之一。更不幸的是,导致大部分用户遭受攻  击的原由是臭名昭着的  goatse.cx  图片  (  请你不要刻意去看  )  。  Slashdot 的安全策略非  常严格:用户只能提交下列的  html  标签:  <b>, <u>, <i>,
<a>,<blockquote>  ,并且  还不支持  CSS.

因此我们创建了这样的策略文件来实现类似的功能。它允许所有文本格式的标签来  直接修饰字体、颜色或者强调作用。

antisamy-ebay.xml

众所周知,  eBay (  http://www.ebay.com/  )  是当下最流行的在线拍卖网站之一。它是一  个面向公众的站点,因此它允许任何人发布一系列富  HTML  的内容。  我们对  eBay  成为一些复杂  XSS  攻击的目标,并对攻击者充满吸引力丝毫不感到奇怪。由于  eBay  允许  输入的内容列表包含了比  Slashdot 更多的富文本内容,所以它的受攻击面也要大得多。下  面的标签看起来是  eBay  允许的(  eBay  没有公开标签的验证规则)  :
<a>,..

antisamy-myspace.xml

MySpace ( http://www.myspace.com/  )  是最流行的一个社交网站之一。用户允许提交  几乎所有的他们想用的  HTML  和  CSS  ,只要不包含  JavaScript 。  MySpace  现在用一  个黑名单来验证用户输入的  HTML  ,这就是为什么它曾受到  Samy  蠕虫攻击  ( http://namb.la/)  的原因。  Samy  蠕虫攻击利用了一个本应该列入黑名单的单词  (eval)  来进行组合碎片攻击的,其实这也是  AntiSamy 立项的原因。

antisamy-anythinggoes.xml

也很难说出一个用这个策略文件的用例。如果你想允许所有有效的  HTML  和  CSS  元素输入(但能拒绝  JavaScript 或跟  CSS  相关的网络钓鱼攻击),你可以使用  这个策略文件。其实即使  MySpace 也没有这么疯狂。然而,它确实提供了一个很  好的参考,因为它包含了对于每个元素的基本规则,所以你在裁剪其它策略文件的  时候可以把它作为一个知识库。

策略文件定制

http://www.owasp.org/index.php/AntiSamy_Directives

AntiSamy.JAVA的使用

首先,老规矩,我们需要一个jar包

使用Maven的,在pom.xml的dependencies中添加如下代码

 

<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.5.3</version>
</dependency>

 

配置web.xml

 

<!-- XSS -->
<filter>
<filter-name>XSS</filter-name>
<filter-class>com.william.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XSS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

 

其中XssFilter为自定义的class,该类必须实现Filter类,在XssFilter类中实现doFilter函数。将策略文件放到和pom.xml平级目录下,然后我们就开始编写XssFilter类。

public class XssFilter implements Filter {
@SuppressWarnings("unused")
private FilterConfig filterConfig;
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new RequestWrapper((HttpServletRequest) request), response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
}

OK,我们需要重写request,新建一个类RequestWrapper,继承HttpServletRequestWrapper,我们需要重写getParameterMap()方法,以及过滤非法html的方法xssClean()

public class RequestWrapper extends HttpServletRequestWrapper {
public RequestWrapper(HttpServletRequest request) {
super(request);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public Map<String,String[]> getParameterMap(){
Map<String,String[]> request_map = super.getParameterMap();
Iterator iterator = request_map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry me = (Map.Entry)iterator.next();
//System.out.println(me.getKey()+":");
String[] values = (String[])me.getValue();
for(int i = 0 ; i < values.length ; i++){
System.out.println(values[i]);
values[i] = xssClean(values[i]);
}
}
return request_map;
}
private String xssClean(String value) {
        AntiSamy antiSamy = new AntiSamy();
        try {
Policy policy = Policy.getInstance("antisamy-myspace-1.4.4.xml");
//CleanResults cr = antiSamy.scan(dirtyInput, policyFilePath); 
            final CleanResults cr = antiSamy.scan(value, policy);
            //安全的HTML输出
            return cr.getCleanHTML();
        } catch (ScanException e) {
            e.printStackTrace();
        } catch (PolicyException e) {
            e.printStackTrace();
        }
        return value;
}
}

好了,到此为止,我们的AntiSamy就成功添加到项目了。

CSRF 防御方案总结下,无外乎三种:

  1. 用户操作限制,比如验证码;
  2. 请求来源限制,比如限制 HTTP Referer 才能完成操作;
  3. token 验证机制,比如请求数据字段中添加一个 token,响应请求时校验其有效性;

第一种方案明显严重影响了用户体验,而且还有额外的开发成本;第二种方案成本最低,但是并不能保证 100% 安全,而且很有可能会埋坑;第三种方案,可取!

https://www.cnblogs.com/wangdaijun/p/5652864.html

------------------------

1 前言

Antisamy是OWASP(open web application security project)的一个开源项目,其能够对用户输入的html/css/javascript 脚本进行过滤,确保输入满足规范,无法提交恶意脚本。Antisamy被应用在web服务中对存储型和反射性的xss防御,尤其是在存在富文本输入的场景,antisamy能够很好的解决用户输入体验和安全要求之间的冲突。

  • Antisamy的对包含非法字符的用户输入的过滤依赖于策略文件,策略文件规定了antisamy对各个标签、属性的处理方法。策略文件定义的严格与否,决定了antisamy对xss漏洞的防御效果。
  • OWASP中antisamy有java和.net两个项目,这篇文档中仅对java项目进行介绍。从安装、使用及策略文件的定制几个方面讲解如何将antisamy应用到实际项目当中。

2 工具安装

  •  Antisamy的官方下载路径:++https://code.google.com/archive/p/owaspantisamy/downloads++。下载列表中包含antisamy的jar包,同时也包含了几个常用的策略文件。官方下载的链接需要翻墙,为方便使用,将最新版本的antisamy和策略文件放到文档的附件中(见附件1)。
  • Antisamy直接导入到java的工程即可,但是其运行依赖另外三个库:

xercesImpl.jar    http://xerces.apache.org/mirrors.cgi#binary

batik.jar              http://xmlgraphics.apache.org/batik/download.cgi

nekohtml.jar       http://sourceforge.net/projects/nekohtml/

  • 可以通过链接下载,也可以从marven中直接下载。测试过程中使用的是从marven中下载,使用的版本信息如下:

 <orderEntry type=”library” name=”xerces:xercesImpl:2.11.0″ level=”project” />

<orderEntry type=”library” name=”com.nrinaudo:kantan.xpath-nekohtml_2.12:0.1.9″ level=”project” />

<orderEntry type=”library” name=”org.apache.xmlgraphics:batik-script:1.8″ level=”project” />

  • 在导入完成后,在java工程中新建一个类,输入如下代码进行测试,确认安装是否正确。
    1. public class AntiSamyApplication {
    2.     public static void main(String[] args)
    3.     {
    4.         AntiSamy as = new AntiSamy();
    5.         try{
    6.             Policy policy = Policy.getInstance("\\antisamy\\antisamy-tinymce-1.4.4.xml");
    7.             CleanResults cr = as.scan("<div>wwwww<script>alert(1)</script></div>", policy);
    8.             System.out.print(cr.getCleanHTML());
    9.         }
    10.         catch(Exception ex) {
    11.         } ;
    12.     }
    13. }

如果输出结果如下结果,说明安装正确,可以正常使用antisamy了。

  1. "C:\Program Files (x86)\Java\jdk1.8.0_121\bin\java"
  2.   <div>wwwwwdddd</div>
  3.   Process finished with exit code 0

3 使用方法

Antisamy存在两种使用方法,一种是从系统层面,重写request处理相关的功能函数,对用户输入的每一个参数均作过滤验证;另外一种是仅对富文本使用过滤验证;

4 策略文件

4.1 策略文件结构

一个简易的Antisamy的策略文件主体结构如所示:

Antisamy的策略文件为xml格式的,除去xml文件头外,可以为7个部分,下面对各个部分的功能做简单的介绍。

  1. <directives>
  2.     <directive name="omitXmlDeclaration" value="true" />
  3.     <directive name="omitDoctypeDeclaration" value="true" />
  4. </directives>

对应上图中标注为1的部分,主要为全局性配置,对antisamy的过滤验证规则、输入及输出的格式进行全局性的控制。具体字段的意义在后面继续文档中详细介绍。

  1. <common-regexps>
  2.     <regexp name="htmlTitle" value="[a-zA-Z0-9\s\-_',:\[\]!\./\\\(\)&amp;]*" />
  3.     <regexp name="onsiteURL" value="([\p{L}\p{N}\p{Zs}/\.\?=&amp;\-~])+" />
  4.     <regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[A-Za-z0-9]+[~a-zA-Z0-9-_\.@\#\$%&amp;;:,\?=/\+!\(\)]*(\s)*" />
  5. </common-regexps>

对应上图中标注为2的部分,将规则文件中需要使用到的正则表达式相同的部分归总到这,会在后续中需要正则的时候通过name直接引用;

  1. <common-attributes>
  2.     <attribute name="title" description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element">
  3.         <regexp-list>
  4.         <regexp name="htmlTitle" />
  5.         </regexp-list>
  6.     </attribute>
  7. </common-attributes>

对应上图中标注为3的部分,这部分定义了通用的属性需要满足的输入规则,其中包括了标签和css的属性;在后续的tag和css的处理规则中会引用到上述定义的属性。

  1. <global-tag-attributes>
  2.     <attribute name="title" />
  3. </global-tag-attributes>

对应上图中标注为4的部分,这部分定义了所有标签的默认属性需要遵守的规则;需要验证如果标签中为validate,有属性但是不全的场景

  1. <tags-to-encode>
  2.    <tag>g</tag>
  3.    <tag>grin</tag>
  4. </tags-to-encode>

对应上图中标注为5的部分,这部分定义了需要进行编码处理的标签;

  1. <tag-rules>
  2.    <!--  Remove  -->
  3.    <tag name="script" action="remove" />
  4.    <!--  Truncate  -->
  5.    <tag name="br" action="truncate" />
  6.    <!--  Validate -->
  7.    <tag name="p" action="validate">
  8.    <attribute name="align" />
  9.    </tag>
  10. </tag-rules>

对应上图中标注为6的部分,这部分定义了tag的处理规则,共有三种处理方式:

remove:对应的标签直接删除如script标签处理规则为删除,当输入为:

<div><script>alert(1);</script></div>

输出为:

<div>ddd</div>

truncate:对应的标签进行缩短处理,直接删除所有属性,只保留标签和值;如标签dd处理规则为truncate,当输入为:

<dd id='dd00001' align='left'>test</test>

validate:对应的标签的属性进行验证,如果tag中定义了属性的验证规则,按照tag中的规则执行;如果标签中未定义属性,则按照 \<global-tag-attributes\> 中定义的处理;

  1. <css-rules>
  2.     <property name="text-decoration" default="none" description="">
  3.         <category-list>
  4.             <category value="visual" />
  5.         </category-list>
  6.         <literal-list>
  7.             <literal value="underline" />
  8.             <literal value="overline" />
  9.             <literal value="line-through" />
  10.         </literal-list>
  11.     </property>
  12. </css-rules>

对应上图中中标注为7的部分,这部分定义了css的处理规则;

4.2 策略文件详解

4.2.1 策略文件指令[<directives></directives>]

策略文件指令包含13个参数,下面对其参数的意义逐一介绍。

  1. <directives>
  2.     <directive name="useXHTML" value="false"/>
  3.     <directive name="omitXMLDeclaration" value="true"/>
  4.     <directive name="omitDoctypeDeclaration" value="true"/>
  5.     <directive name="formatOutput" value="false"/>
  6.     <directive name="maxInputSize" value="100000"/>
  7.     <directive name="embedStyleSheets" value="false"/>
  8.     <directive name="maxStyleSheetImports" value="1"/>
  9.     <directive name="connectionTimeout" value="1000"/>
  10.     <directive name="preserveComments" value="false"/>
  11.     <directive name="nofollowAnchors" value="false"/>
  12.     <directive name="validateParamAsEmbed" value="false"/>
  13.     <directive name="preserveSpace" value="false"/>
  14.     <directive name="onUnknownTag" value="remove"/>
  15. </directives>

下面的介绍中使用到的样例均以antisamy-myspace-1.4.4.xml为基础进行修改

useXHML>

类型:boolean

默认值: false

功能:开启后,antisamy的结果将按照XHTML的格式输出;默认使用HTML;

注:XHTML和HTML的主要区别在于XHMTL格式更加严格,元素必须正确的嵌套,必须闭合,标签名要小写,必须要有根元素;

在测试过程中,发现该参数实际上对输出的结果没什么影响。

omitXMLDeclaration>

类型:boolean

默认值:true
功能:按照文档描述,在开启时antisamy自动添加xml的头

测试时发现该参数对输出没啥影响。

omitDoctypeDeclaration>

类型: boolean

默认值:true

功能:在值为false时,antisamy在输出结果中自动添加html头

当输入为:

<div class='navWrapper'><p>sec_test<script>alert(1);</script></p></div>

输出结果为:

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  2.                       "http://www.w3.org/TR/html4/strict.dtd">
  3. <div class="navWrapper">
  4.   <p>sec_test</p>
  5. </div>

formatOutput>

类型:boolean

默认值:true

功能:开启后,antisamy会将输出结果格式化,使可读性更好;

默认是开启的,在关闭后,当输入为:

<div class='navWrapper'><p>sec_test<script>alert(1);</script></p></div>

输出结果为:

<div class="navWrapper"><p>sec_test</p></div>

注:可以和omitDoctypeDeclaration的结果对比着看。

maxInputSize>

类型:int
默认值:100000

功能:用于验证的最长字符串长度,单位bytes;

embedStyleSheets>

类型:boolean

默认值:false

功能:在开启css过滤功能后,该指令确认是否将引用的css文件下载下来并导入到用户输入一起作为检查的输入;

maxStyleSheetImports>

类型:int
默认值:1

功能:配合embedStyleSheets使用,指定在输入中可以下载css文件的个数;

connecttionTimeout>

类型:int

默认值:1000

功能:配合embedStyleSheets使用,指定在下载css文件时的超时时长,单位为毫秒;

preserveComments>

类型:boolean

默认值:false

功能:开启后,保留输入中的注释行;

nofollowAnchors>

类型:boolean

默认值:falsle

功能:开启后,在锚点标签(<a>)后添加rel=“nofollow”属性,防止跳转到其他页面

开启后当输入为:

<div><a href='www.baid.com'>click</a></div>

输出结果为:

  1. <div>
  2.   <a href="www.baid.com" rel="nofollow">click</a></div>

validateParamAsEmbed>

类型:booblean

默认值:false

功能:开启后,antisamy将<embed>标签的属性和嵌入到embed标签内的<param>标签的属性相同的规则处理,主要用于在需要用户输入的视频站点。

preserveSpace>

类型:boolean

默认值:false

功能:开启后,保留输入中的空格;

onUnknowTag>

类型:String

默认值:remove

功能:对未知tag的处理规则,默认为删除,可以修改为encode;

4.2.2 通用正则表达式 [<common-regexps> </common-regexps>]

其定义的格式为:

<regexp name="htmlId" value="[a-zA-Z0-9\:\-_\.]+"/>

htmlId为正则的名称,通过名称被引用

value后面是具体的正则表达式的内容  该部分可以参考antisamy中样例规则文件编写;

如有特殊需要,正则表达式可以参考网上其他资料进行编写。

4.2.3 通用属性 [<common-attributes> </common-attributes>]

通用属性义如下:

  1. <attribute name="media">
  2.     <regexp-list>
  3.         <regexp value="[a-zA-Z0-9,\-\s]+"/>
  4.         <regexp name="htmlId"/>
  5.     </regexp-list>
  6.     <literal-list>
  7.         <literal value="screen"/>
  8.         <literal value="tty"/>
  9.         <literal value="tv"/>
  10.     </literal-list>
  11. </attribute>

“attribute name”为标签的名称,与html的tag名称保持一致;

“regexp name”为标签需要满足的正则表达式的名称,其在<common-regexps>中定义;

“regexp value”为标签需要满足的正则表达式;

可以通过literal直接指定属性的值;如media的值可以满足上面两个的正则表达式外,也可以为screen、tty、tv中的一个

注:<regexp-list><literal-list>中的值均可以为多个

4.2.4 全局tag属性<global-tag-attributes>

其定义和4.2.3中通用属性的定义无区别,只能功能不同;

具体功能在后面tag的规则介绍(4.2.7)中展示;

4.2.5 编码处理tag<tag-to-encode>

此处标识的tag将在输出中进行编码;

其定义的格式为:

  1. <tags-to-encode>
  2.    <tag>g</tag>
  3.    <tag>grin</tag>
  4. </tags-to-encode>

但是实际测试的时候,并未生效。

4.2.6 tag处理规则<tag-rules>

tag-rules的定义规则如下:

  1. <tag name="button" action="validate">
  2.     <attribute name="name"/>
  3.     <attribute name="value">
  4.    <regexp-list>
  5.    <regexp name="anything"/>
  6.    </regexp-list>
  7.     </attribute>
  8.     <attribute name="type">
  9.         <literal-list>
  10.             <literal value="submit"/>
  11.             <literal value="reset"/>
  12.             <literal value="button"/>
  13.         </literal-list>
  14.     </attribute>
  15. </tag>

tagc-rule的action有三种:remove、validate、truncate,各个动作的功能在4.1中介绍过,不再赘述.

其中有一种场景需要注意:

<tag name="h1" action="validate"/>

这种标签中action是validate,但是标签的属性需要遵守的正则却没有标识出来;在这个时候,4.2.4中全局tag属性中定义的属性就起作用了。上面这种类型的标签就需要遵守4.2.4中定义的全局属性;

如:h1标签处理规则如下:

<tag name="h1" action="validate"/>

输入为:

<div><h1 id='h111' align='center'>h1 title</h1></div>

输出为:

  1. <div>
  2.   <h1 id="h111">h1 title</h1></div>

global-tag-attribute中有”id”, “style”,”title”,”class”,”lang”这5个标签,不包括align,所以在输出中就被过滤掉了。

4.2.7 css处理规则<css-rules>

css-rules定义如下:

  1. <property name="background-color" description="This property sets the background color of an element, either a &lt;color&gt; value or the keyword 'transparent', to make the underlying colors shine through.">
  2.     <literal-list>
  3.         <literal value="transparent"/>
  4.         <literal value="inherit"/>
  5.     </literal-list>
  6.     <regexp-list>
  7.         <regexp name="colorName"/>
  8.         <regexp name="colorCode"/>
  9.         <regexp name="rgbCode"/>
  10.         <regexp name="systemColor"/>
  11.     </regexp-list>
  12. </property>

从上面可以看出,css过滤规格的定义和tag的基本相同;但是css有一些特殊的字段,如:

  1. <property name="background" description="The 'background' property is a shorthand property for setting the individual background properties (i.e., 'background-color', 'background-image', 'background-repeat', 'background-attachment' and 'background-position') at the same place in the style sheet.">
  2.     <literal-list>
  3.         <literal value="inherit"/>
  4.     </literal-list>
  5.     <shorthand-list>
  6.         <shorthand name="background-color"/>
  7.         <shorthand name="background-image"/>
  8.         <shorthand name="background-repeat"/>
  9.         <shorthand name="background-attachment"/>
  10.         <shorthand name="background-position"/>
  11.     </shorthand-list>
  12. </property>

相比tag的过滤规则,css增加了shorthand-list,为css的自有语法。意味着如果background有多个值,说明使用了css的缩写,同时需要满足shorthand中规定的属性的过滤规则。

4.3 通用策略文件

5 Antisamy代码简介

antisamy对html进行扫描的主要流程如下:

其中

recursiveValidateTag(tmp, currentStackDepth);

为antisamy最终执行扫描的函数,其通过递归调用对html中每一个标签根据规则文件的定义进行处理

 

https://blog.csdn.net/raychiu757374816/article/details/79016101

一页纸工作整理术

有时候,你是不是想把该做的事一口气处理完,却发现仍旧天天拖延?

有时候,想让自己的工作更高效、生活更轻松,却无从下手?

工作、生活实属不易。无论何时,我们都要抓住最重要的事,好好工作,好好生活。

身为职场中的辛苦小蜂蜜,我绝对是有上进心且埋头苦干的一个。在大城市,如果不拿出点真本事来,领导和同事绝对会视你为空气。对于这一点,相信你也深有体会。

但是,长期坚持下来,拼命三郎的我越发觉得自己被忙碌的生活缚住了手脚,不敢懈怠却心生疲惫。甚至,有时都会怀疑自己会不会“过劳死”……

“我也知道这样不好,但是有什么解决办法?”

 

在日常工作中,是我没有找到适合自己的工作方法,还是因为我太笨、反应迟钝?恰逢周末,待各种忙过之后,无意中在亚马逊上发现了一本好书。

据说,用一张纸、一支笔,挣脱创意泥潭,轻轻松松就能解决工作中出现的各种难题。

这,究竟是何种方法呢?

一支笔 + 一张纸 = 一种思考方式。

它是视觉化思考领域的必读作品《一页纸工作整理术》,只需四天,就能让读者学会受用终生的视觉化思考技能,大幅提高工作效率。

原来如此!那么,它的作者是何许人物呢?跟随小编一起来了解下哦!

丹·罗姆,全球首个线上视觉化思考训练营“餐巾纸学院”创始人,靠着一支笔、一张纸横扫全球,帮助各个行业的公司运用视觉化思考工具,解决各种商业问题。

他的客户包括谷歌、eBay、IBM、通用电气、沃尔玛、微软、时代华纳、纽约联邦储备银行、辉瑞制药等全球500强企业。

目 录

导言:用画图解决问题

第一章本书的使用方法

第二章开场白:为画图做好准备

第三章你有多少种解读方式?

第四章读本书前你应该知道的

……

不得不说,新兴技术为我们节省了很多时间,但我们用来填充这些“多出来的”时间的方式,往往就是排更多的行程。

只要会画圆圈和直线,你就能打破传统思考模式,用最轻松、最直观的方式呈现解决问题的诀窍!

在你的工作或生活中,不知是否出现过这样的问题。比如:

明明是很简单的一件事情,沟通起来却花了很长时间?

每次碰到新问题,下大力气研究也找不到解决的突破口?

手里的项目从很久前就开始规划,但总在最后关头才匆忙完成?

……

时间紧、任务重、头绪杂,在工作中提高效率非常重要。研究显示,通过听觉获得的信息,只能记住10%。透过文字,是20%。经由图像,则可以记住80%。

既然如此,为什么不试着用图表达你的想法?

画图的过程,就是理清思路的过程。只有当你重新拿起纸笔开始写写画画,才能真正专注于思考本身。用图思考一看就懂,过目不忘,才是最具效率的工作方式。

书上说,只要四天,就能让你学会受用终生的高效工作法

第一天,你将重新认识自己与生俱来的三种视觉化思考工具。

第二天,你将学会运用视觉化思考观察世界的六种全新方式。

第三天,你将掌握把无意义的涂鸦化腐朽为神奇的五个技巧。

第四天,你将彻底唤醒自己沉睡已久的视觉思考力!

《新闻周刊》说:“丹•罗姆告诉我们,什么时候你该闭嘴,画一张图比说一千句有效得多。”

《让创意更有黏性》作者奇普·希思说:“花几个小时读完这本书就能掌握一种受用终生的思考方式,去哪儿找这么划算的买卖?”

既是如此,那么,从现在开始,让我们丢掉电脑、丢掉手机、丢掉PPT,从一支笔、一张纸出发吧

------------

https://pan.baidu.com/s/12ZZAl?fid=497219585436321