核心流程实现四 原生实现Java程序漏洞讲解
我们的程序并不安全
到目前为止 核心流程已经实现
但是想要上线 安全么
首先如果用户提交恶意代码怎么办
执行阻塞 占用资源不释放
程序卡死
注意类名要改为Main 包名一定要去掉
如果这种代码放到服务器中
会无限占用时间
package work.bigdata1421.dduojcodesandbox.unsafe;/*** 无限睡眠 阻塞程序的执行*/
public class SleepError {public static void main(String[] args) throws InterruptedException{long ONE_HOUR=60*60*1000L;Thread.sleep(ONE_HOUR);System.out.println("睡完了");}
}
占用内存 不释放
无限占用服务器时间
package work.bigdata1421.dduojcodesandbox.unsafe;import java.util.ArrayList;
import java.util.List;/*** 无限占用空间(浪费系统内存)*/
public class MemoryError {public static void main(String[] args) throws InterruptedException {List<byte[]> bytes = new ArrayList<>();while (true) {bytes.add(new byte[10000]);}}
}
实际运行中
我们会发现内存占用一定空间后 程序就会自动报错
堆内存溢出
这是JVM的一个保护机制
占用内存 不释放
我们可以设置JVM的启动内存
我们有一个工具 专门来计算JVM的内存的
JVisualVM工具 或者 Jconsole工具
可以连接到虚拟机上 动态的来查看JVM的状态 运行状态
读写文件
我们要写一个文件 读取到数据库的密码
我们可以写这样一个程序
也是不安全的
package work.bigdata1421.dduojcodesandbox.unsafe;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;/*** 读取服务器文件(文件信息泄露)*/
public class ReadFileError {public static void main(String[] args) throws InterruptedException, IOException {String userDir = System.getProperty("user.dir");String filePath = userDir + File.separator + "src/main/resources/application.yml";List<String> allLines = Files.readAllLines(Paths.get(filePath));System.out.println(String.join("\n", allLines));}
}
运行一下
发现读取出来了
写文件,越权植入木马
java -version 2>&1
向服务器写文件
package work.bigdata1421.dduojcodesandbox.unsafe;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;/*** 向服务器写文件(植入危险程序)*/
public class WriteFileError {public static void main(String[] args) throws InterruptedException, IOException {String userDir = System.getProperty("user.dir");String filePath = userDir + File.separator + "src/main/resources/木马程序.bat";String errorProgram = "java -version 2>&1";Files.write(Paths.get(filePath), Arrays.asList(errorProgram));System.out.println("写木马成功,你完了哈哈");}
}
运行其他危险程序
直接通过Process执行危险程序
package work.bigdata1421.dduojcodesandbox.unsafe;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;/*** 运行其他程序(比如危险木马)*/
public class RunFileError {public static void main(String[] args) throws InterruptedException, IOException {String userDir = System.getProperty("user.dir");String filePath = userDir + File.separator + "src/main/resources/木马程序.bat";Process process = Runtime.getRuntime().exec(filePath);process.waitFor();// 分批获取进程的正常输出BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));// 逐行读取String compileOutputLine;while ((compileOutputLine = bufferedReader.readLine()) != null) {System.out.println(compileOutputLine);}System.out.println("执行异常程序成功");}
}
Java原生超时资源权限控制
超时控制
判断运行时间
主线程在运行程序 我们可以新建一个线程 叫做监控线程
首先我们定义超时时间
// 定义超时时间
private static final long TIME_OUT = 10000L;
创建守护线程
先让线程睡一会
睡醒了直接杀死主线程
Process runProcess = Runtime.getRuntime().exec(runCmd);
// 超时控制
new Thread(() ->{try {Thread.sleep(TIME_OUT);System.out.println("超时了 中断");runProcess.destroy();}catch (InterruptedException e){e.printStackTrace();throw new RuntimeException();}
}).start();
限制给用户分配的资源
我们不能让每个Java进程的执行占用的JVM最大堆内存空间都和系统的一致
实际上应该小一点
比如说256MB
在启动JVM的参数 可以启动JVM的参数 -Xmx256m 最大堆空间大小 -Xms(初始堆空间大小)
可以保护系统
注意 -Xmx参数 JVM的堆内存限制 不等同与系统实际占用的最大内存 可能会超出
如果需要更严格的内存限制 要在系统层面去限制 而不是JVM层面的限制
如果是Linux系统 可以使用cgroup来实现对某个进程CPU 内存等资源的分配
限制代码 黑白名单
先定义一个黑白名单 比如那些操作是禁止的
// 定义黑白名单
private static final List<String> blackList = Arrays.asList("Files","exec");
危险代码其实都不用编译 直接在最开始进行校验
我们在开始的时候就用字典树进行校验
字典树是HuTool的一个工具类 WordTree
作用是可以用更小的空间存储更多的敏感词汇
实现更高效的敏感词查找
private static final List<String> blackList = Arrays.asList("Files","exec");private static final WordTree wordTree;static {// 初始化字典树wordTree = new WordTree();wordTree.addWords(blackList);}
字典树的初始化
可以用静态代码块去执行
private static final List<String> blackList = Arrays.asList("Files","exec");private static final WordTree wordTree;static {// 初始化字典树wordTree = new WordTree();wordTree.addWords(blackList);}