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