TomProbe的网络安全可信属性

 

主要有四点:

 

一、您的网站因Web Server发生了安全事故,可向我公司追责(民事赔偿责任和刑事责任)。采用TomProbe,必然要采用我公司改写版Tomcat,因Web Server发生的安全事故,理所当然找我公司追责,这在法律上毫无疑问地成立(我公司在合同里也明确这点),而且追责起来很容易,因我公司是国内公司。采用Apache组织的原版Tomcat会怎样?因Web Server发生的安全事故,您可能得通过国际法向Apache组织追责,难度要大得多;当中美关系彻底破裂时,您可能不但无法向Apache组织追责,而且祖国还要向您问责。

 

我公司何以有这份能力和自信?只有精通Tomcat源代码、精通到每一个角落,才能写好TomProbe。

 

 

二、确保对Tomcat源代码的重新编译。Tomcat是开源的,但我且问你:你平时用来开发运行的Tomcat与Tomcat的源代码是一致的吗?就是说,从网络安全可信的角度,您在使用Tomcat前,应该对Tomcat源代码重新编译一遍。但绝大多数人不会去编译Tomcat源代码。当然,我们应该相信Tomcat的发布包与源代码是一致的。

但没有编译而直接采用Tomcat发布包毕竟会在心理上留下一些担忧,这种精神上的恍惚在某些时候会造成大后果,例如:查找安全问题时,多了一个不必要的头绪;再例如:导致作出错误的决定,最后造成重大损失或灾难。

 

三、在您的IT系统遭到黑客攻击或勒索时,我公司帮助您分析定位原因。Web Server的安全性比数据库更重要,经过Web Server的每一个Byte的意思对Web Server作者而言都很简单容易。在您的IT系统遭到黑客攻击或勒索时,您的IT系统因采用了我公司改写的Tomcat,我公司自然会帮助您分析定位原因。如果您的IT系统是采用正版的Tomcat,会怎样?Tomcat是一个团队编写的,您极难请到这个团队的所有成员来帮您分析定位原因,恐怕您连Tomcat的主程也请不到!但我公司不然,会派出精通Tomcat每一个角落的专家帮助您。

 

四、封堵了安全隐患。我公司改写的Tomcat将来会改正Tomcat网络安全方面有问题的代码。Tomcat并非完美到一点网络安全问题都没有。在这里举一例:Tomcat8、Tomcat9、Tomcat10的StandardServer.java的代码是这样的:

 

public void await(){

  if (getPortWithOffset()==-2){

    return;

  }

  if (getPortWithOffset()==-1){

    try{

      awaitThread=Thread.currentThread();

      while (!stopAwait){

        try{

          Thread.sleep(10000);

        } 

        catch (InterruptedException ex){

        }

      }

finally{

      awaitThread=null;

    }

    return;

  }

  try{

    awaitSocket=new ServerSocket(getPortWithOffset(), 1,

                    InetAddress.getByName(address));

  } 

  catch (IOException e){

log.error(sm.getString("standardServer.awaitSocket.fail",address, 

String.valueOf(getPortWithOffset()), String.valueOf(getPort()),

    String.valueOf(getPortOffset())), e);

    return;

  }

  try{

    awaitThread=Thread.currentThread();

    while (!stopAwait){

      ServerSocket serverSocket=awaitSocket;

      if (serverSocket==null){

        break;

      }

      Socket socket=null;

      StringBuilder command=new StringBuilder();

      try{

        InputStream stream;

        long acceptStartTime=System.currentTimeMillis();

        try{

          socket=serverSocket.accept();

          socket.setSoTimeout(10*1000);

          stream=socket.getInputStream();

        } 

        catch (SocketTimeoutException ste){

          log.warn(sm.getString("standardServer.accept.timeout",

          Long.valueOf(System.currentTimeMillis() - acceptStartTime)), 

                       ste);

          continue;

        } 

        catch (AccessControlException ace){

          log.warn(sm.getString("standardServer.accept.security"), 

                   ace);

          continue;

        } 

        catch (IOException e){

          if (stopAwait){

            break;

          }

          log.error(sm.getString("standardServer.accept.error"), e);

          break;

        }

        int expected=1024; 

        while (expected<shutdown.length()){

           if (random==null){

             random=new Random();

           }

           expected+=(random.nextInt() % 1024);

        }

        while (expected>0){

          int ch=-1;

          try{

            ch=stream.read();

          } 

          catch (IOException e){

            log.warn(sm.getString("standardServer.accept.readError"), 

                     e);

            ch=-1;

          }

          if (ch<32 || ch==127){

             break;

          }

          command.append((char)ch);

          expected--;

        }

      } 

      finally{

        try{

          if (socket!=null){

            socket.close();

          }

        } 

        catch (IOException e){

        }

      }

      boolean match=command.toString().equals(shutdown);

      if (match){

        log.info(sm.getString("standardServer.shutdownViaPort"));

        break;

      } 

      else{

       log.warn(sm.getString("standardServer.invalidShutdownCommand", 

                command.toString()));

      }

    }

  } 

  finally{

    ServerSocket serverSocket=awaitSocket;

    awaitThread=null;

    awaitSocket=null;

    if (serverSocket!=null){

      try{

        serverSocket.close();

      } 

      catch (IOException e){

      }

    }

  }

}

 

这段代码的作用是Kill Tomcat。当您敲shutdown.bat或shutdown.sh时,这段代码执行,就把Tomcat进程停止了。

 

但您运行如下KillAnyTomcat程序:

 

import java.io.*;

import java.net.Socket;

import java.util.*;

 

public class KillAnyTomcat{

 

  Socket sk;

  InputStream in;

  OutputStream ou;

 

  public KillAnyTomcat(){

  }

 

  public static void main(String[] args){

    KillAnyTomcat kill=new KillAnyTomcat();

    kill.kkk();

  }

 

  private void kkk(){

    try{

      System.out.println("to sk=...");

 

      sk=new Socket("127.0.0.1", 8005);

 

      System.out.println("sk="+sk);

 

      in=sk.getInputStream();

 

      System.out.println("in="+in);

 

      ou=sk.getOutputStream();

 

      System.out.println("ou="+ou);

 

      ou.write("SHUTDOWN".getBytes());

      ou.flush();

 

      System.out.println("send end!");

    }

    catch (Throwable ex1){

      ex1.printStackTrace();

    }

    try{

      sk.close();

    }

    catch (Throwable ex1){

    }

  }

}

 

是不是也把Tomcat(本机运行的)Kill了?实践上,可通过防火墙屏蔽对shutdown端口(8005)的访问,防止黑客程序停止Tomcat。但shutdown端口是可以变动的,防火墙可以轻松屏蔽吗?

 

但不管怎样,以上Tomcat程序,我公司改写版Tomcat将改写成如下样子(防黑客攻击、更安全):

 

public void await(){

  if (getPortWithOffset()==-2){

    return;

  }

  if (getPortWithOffset()==-1){

    try{

      awaitThread=Thread.currentThread();

      while (!stopAwait){

        try{

          Thread.sleep(10000);

        } 

        catch (InterruptedException ex){

        }

      }

finally{

      awaitThread=null;

    }

    return;

  }

  try{

    awaitSocket=new ServerSocket(getPortWithOffset(), 1,

                    InetAddress.getByName(address));

  } 

  catch (IOException e){

log.error(sm.getString("standardServer.awaitSocket.fail",address, 

String.valueOf(getPortWithOffset()), String.valueOf(getPort()),

    String.valueOf(getPortOffset())), e);

    return;

  }

  try{

    awaitThread=Thread.currentThread();

    while (!stopAwait){

      ServerSocket serverSocket=awaitSocket;

      if (serverSocket==null){

        break;

      }

      try{      

        Thread.sleep(2000);  //2s

      }

      catch (Throwable ex1){

      }

      Socket socket=null;

      StringBuilder command=new StringBuilder();

      try{

        InputStream stream;

        long acceptStartTime=System.currentTimeMillis();

        try{

          socket=serverSocket.accept();

          socket.setSoTimeout(10*1000);

          stream=socket.getInputStream();

        } 

        catch (SocketTimeoutException ste){

          log.warn(sm.getString("standardServer.accept.timeout",

          Long.valueOf(System.currentTimeMillis() - acceptStartTime)), 

                       ste);

          continue;

        } 

        catch (AccessControlException ace){

          log.warn(sm.getString("standardServer.accept.security"), 

                   ace);

          continue;

        } 

        catch (IOException e){

          if (stopAwait){

            break;

          }

          log.error(sm.getString("standardServer.accept.error"), e);

          break;

        }

        int expected=1024; 

        while (expected<shutdown.length()){

           if (random==null){

             random=new Random();

           }

           expected+=(random.nextInt() % 1024);

        }

        while (expected>0){

          int ch=-1;

          try{

            ch=stream.read();

          } 

          catch (IOException e){

            log.warn(sm.getString("standardServer.accept.readError"), 

                     e);

            ch=-1;

          }

          if (ch<32 || ch==127){

             break;

          }

          command.append((char)ch);

          expected--;

        }

      } 

      finally{

        try{

          if (socket!=null){

            socket.close();

          }

        } 

        catch (IOException e){

        }

      }

      boolean match=command.toString().equals(shutdown);

      if (match){

        String remoteAddr=socket.getInetAddress().getHostAddress(); 

        if (remoteAddr!=null && (remoteAddr.equals("localhost") || 

           remoteAddr.equals("127.0.0.1"))){

        }

        else{

          match=false;

        } 

      }

      if (match){

        log.info(sm.getString("standardServer.shutdownViaPort"));

        break;

      } 

      else{

       log.warn(sm.getString("standardServer.invalidShutdownCommand", 

                command.toString()));

      }

    }

  } 

  finally{

    ServerSocket serverSocket=awaitSocket;

    awaitThread=null;

    awaitSocket=null;

    if (serverSocket!=null){

      try{

        serverSocket.close();

      } 

      catch (IOException e){

      }

    }

  }

}