近期打算做一个插件化的白盒静态代码安全审计自动化平台和黑盒网站安全审计自动化平台。现在开源或半开源做黑盒网站安全扫描的平台,大多是基于python脚本,安全人员贡献python脚本插件增强平台功能。对自己或身边开发人员,对java语言更熟悉,为了后期维护打算采用java写一个这样的平台。另外白盒代码安全扫描也有Fortify等收费软件,或依赖PMD做代码分析,不过比如新增了什么安全问题,需要自定义或扩展就比较麻烦。

比如一个简单的:现在用struts2存在漏洞,现在需要升级到2.3.28版本,于是我写一个插件,判断pom.xml里如果有配置struts2,只要版本不是2.8.2就认为存在漏洞。平台提供下载制定SVN或GIT或其他服务器的代码,然后执行该插件即可扫描哪些项目有问题了。

该项目最近几天和同事一起做了一个初步版本,想法还有不完善的地方,作为后期参考,主要目的是先搭建一个能用的架子出来。

首先提供插件,那就需要有一个独立的jar项目作为插件依赖的接口项目,它需要定义插件的接口和交互的对象,接口需要至少2个方法:验证该插件是否可扫描,执行插件逻辑扫描,比如白盒扫描插件接口定义如下:

public interface IWhiteboxService {
/**
* 验证该文件是否符合规则需求
*
* @param inputFile
* 被扫描的文件信息
* @return 验证结果
*/
ValidateResult validate(InputFile inputFile); /**
* 如果validate验证通过,则开始扫描
*
* @param inputFile
* 被扫描的文件信息
* @return 扫描结果
*/
List<ScanResult> scan(InputFile inputFile);
}

  然后需要有一个统一的服务,用于调用插件执行代码扫描。通过网站或定时任务只需要调用该服务即可。后面可以做扫描任务只扫描哪些插件,比如扫描所有插件代码:

	public void scan(Whitetask task) {
//todo:循环插件扫描。或后期根据任务和插件关闭表扫描
if (null == task || StringUtil.isNull(task.getCodepath())) {
//todo:记录日志,任务表有问题
return;
}
/*
* 1、读取whiteplugin表所有插件并缓存插件对应的代码,不用每次反射
* 2、循环task.getCodepath()路径下所有文件,默认java文件,根据getFileext()的文件类型和getExcluderule()排除的文件而定
* 根据循环后的文件存储到LIST集合里,循环时排除文件是为了减少LIST的内容
* 3、根据循环LIST结果再循环所有文件,调用插件的代码进行扫描
* 4、扫描结果插入whitescanresult表
* 5、循环完毕后,修改whitetask表的当前任务扫描完毕
*/
List<Whiteplugin> allPlugins = whitepluginService.getAll();
if (null == allPlugins || allPlugins.size() < 1) {
//todo:记录日志,没有可用的插件
return;
}
List<WhitePluginData> allPluginDatas = null;
if (null != allPlugins) {
allPluginDatas = WhitePluginGenerator.generate(allPlugins);
}
if (null == allPluginDatas || allPluginDatas.size() < 1) {
//todo:记录日志,有插件,转换失败
return;
}
List<FileData> fileDatas = FileGenerator.generate(task.getCodepath(), task.getFileext(), task.getExcluderule());
doScan(fileDatas, allPluginDatas, task);
}

  真正扫描的doScan方法:

	public void doScan(List<FileData> fileDatas, List<WhitePluginData> allPluginDatas, Whitetask task) {
if (null == fileDatas || null == allPluginDatas || fileDatas.size() < 1 || allPluginDatas.size() < 1) {
return;
}
for (int i = 0; i < fileDatas.size(); i++) {
//循环每个文件调用每个插件
FileData tempFileData = fileDatas.get(i);
for (int j = 0; j < allPluginDatas.size(); j++) {
//循环每个插件
IWhiteboxService whiteboxService = allPluginDatas.get(j).getWhiteboxService();
InputFile inputFile = new InputFile();
inputFile.setContents(tempFileData.getContent());
inputFile.setFileExt(FileUtil.getEXT(tempFileData.getFileName()));
inputFile.setFileName(tempFileData.getFileName());
//todo:这里传递的是绝对路径,不是包路径
inputFile.setPackagePath(tempFileData.getPath());
List<InputFileContent> inputFileContents = getFileContents(tempFileData.getContent());
inputFile.setFileContents(inputFileContents); ValidateResult validateResult = whiteboxService.validate(inputFile);
if (null != validateResult && validateResult.isIssuccess()) {
List<ScanResult> scanResults = whiteboxService.scan(inputFile);
if (null != scanResults && scanResults.size() > 0) {
//插入数据库
for (int z = 0; z < scanResults.size(); z++) {
Whitescanresult whitescanresult = getScanResult(inputFile, scanResults.get(z), allPluginDatas.get(j), task);
whiteScanResultService.save(whitescanresult);
}
}
}
}
}
}

  根据插件扫描完成后,把结果插入扫描结果表。核心的表结构包括任务表、插件表、扫描结果表,相关主要表字段如下:

DROP TABLE IF EXISTS `vulfeel`.`whiteplugin`;
CREATE TABLE `vulfeel`.`whiteplugin` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(200) DEFAULT '' COMMENT '插件名称',
`type` tinyint(4) DEFAULT NULL COMMENT '后期扩展分类',
`importlevel` tinyint(4) DEFAULT NULL COMMENT '插件重要性,1轻微,2一般,3重要',
`classpath` varchar(2000) DEFAULT NULL COMMENT '插件包路径,比如com.xx.vulfeel.plugin.a',
`filename` varchar(200) DEFAULT NULL COMMENT 'class名称或jar名称,如果插件是jar包则是jar包名称,比如a.jar;否则是class名称,比如a.class',
`functions` varchar(2000) DEFAULT NULL COMMENT '插件功能描述',
`version` varchar(200) DEFAULT NULL COMMENT '插件版本',
`refurl` varchar(1000) DEFAULT NULL COMMENT '插件原理参考URL等内容',
`userid` int(11) DEFAULT NULL COMMENT '插件提供者用户ID',
`createtime` datetime DEFAULT NULL,
`remark` varchar(2000) DEFAULT NULL COMMENT '插件其他备注',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='白盒扫描插件表'; DROP TABLE IF EXISTS `vulfeel`.`whitescanresult`;
CREATE TABLE `vulfeel`.`whitescanresult` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`taskid` int(11) DEFAULT NULL COMMENT '关联任务表ID',
`pluginid` int(11) DEFAULT NULL COMMENT '关联问题插件ID',
`impactlevel` tinyint(4) DEFAULT NULL COMMENT '影响程度,1轻微,2一般,3重要,主要和插件表的importlevel关联',
`classpath` varchar(2000) DEFAULT NULL COMMENT '插件包路径,比如com.xx.vulfeel.plugin.a',
`filename` varchar(200) DEFAULT NULL COMMENT 'class名称或jar名称,如果插件是jar包则是jar包名称,比如a.jar;否则是class名称,比如a.class',
`startline` int(11) DEFAULT NULL COMMENT '问题开始代码行',
`stopline` int(11) DEFAULT NULL COMMENT '问题结束代码行',
`createtime` datetime DEFAULT NULL,
`remark` varchar(2000) DEFAULT NULL COMMENT '其他备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='白盒扫描结果表'; DROP TABLE IF EXISTS `vulfeel`.`whitetask`;
CREATE TABLE `vulfeel`.`whitetask` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(200) DEFAULT NULL COMMENT '任务名称',
`codepath` varchar(1000) DEFAULT NULL COMMENT '代码路径,不依赖SVN还是GIT等,只需要传入代码地址即可',
`fileext` varchar(200) DEFAULT NULL COMMENT '扫描的文件格式,默认java文件,逗号分隔,比如:java,js',
`excluderule` varchar(1000) DEFAULT NULL COMMENT '不扫描的路径规则,::两个冒号分割正则,比如:.*test::js$::css$',
`status` tinyint(4) DEFAULT NULL COMMENT '任务状态,1初始任务,2正在执行,3任务正常结束,4任务异常结束',
`userid` int(11) DEFAULT NULL COMMENT '关联创建任务的用户ID',
`createtime` datetime DEFAULT NULL,
`lastmodifytime` datetime DEFAULT NULL,
`remark` varchar(2000) DEFAULT NULL COMMENT '其他备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='白盒扫描任务';

  建立任务后,只需要点击执行扫描,即可根据插件扫描出结果,查看结果:

比如一个简单的扫描sql注入的插件扫描结果如上,插件代码如下:

public class SqlInjectPlugin implements IWhiteboxService {

	@Override
public ValidateResult validate(InputFile inputFile) {
// TODO Auto-generated method stub
ValidateResult result = new ValidateResult();
result.setIssuccess(false);
if (null == inputFile || null == inputFile.getFileContents()) {
return result;
}
if (inputFile.getPackagePath().contains("dao")) {
result.setIssuccess(true);
} return result;
} @Override
public List<ScanResult> scan(InputFile inputFile) {
// TODO Auto-generated method stub
List<ScanResult> result = new ArrayList<ScanResult>();
ScanResult scanResult = new ScanResult();
if (null == inputFile || null == inputFile.getFileContents()) {
return result;
}
Pattern pattern = Pattern.compile("(\"[^\"]+\"|\\w+)\\s*(\\+|\\+=)\\s*\\w+");
if (inputFile.getPackagePath().contains("dao")) {
//只扫描包路径有dao的文件
//循环inputFile的每一行,如果有拼接sql就说明存在注入
for (int i = 0; i < inputFile.getFileContents().size(); i++) {
InputFileContent inputFileContent = inputFile.getFileContents().get(i);
Matcher matcher = pattern.matcher(inputFileContent.getContent());
if (matcher.find()) {
scanResult.setStartline(inputFileContent.getLine());
scanResult.setStopline(inputFileContent.getLine());
scanResult.setRemark("存在sql拼接!");
result.add(scanResult);
}
}
}
return result;
} }

  现在项目主要是搭建一个架子,web黑盒扫描的架子也类试,白盒扫描现在是静态代码扫描,没有用PMD等对代码生成语法树分析等,还非常简单。后面有时间再完善和扩展。

如需要转载请注明来自:http://lawson.cnblogs.com/

JAVA语言搭建白盒静态代码、黑盒网站插件式自动化安全审计平台的更多相关文章

  1. java 子类、父类中静态代码块、字段,非静态代码块、字段以及构造函数的初始化顺序和次数

    一个类中的数据初始化顺序是面试官非常喜欢出的面试题之一,本文用一个实例来介绍java中子类.父类中静态代码块.字段,非静态代码块.字段以及构造函数的执行顺序和次数. 一.包结构

  2. 白盒静态自动化测试工具:FindBugs使用指南

    目 录     1     FINDBUGS介绍     2     在ECLIPSE中安装FINDBUGS插件     3     在ECLIPSE中使用FINDBUGS操作步骤     3.1   ...

  3. java面试基础题------》Java 中的父子类静态代码块,代码块,构造方法执行顺序

    4.指出下面程序的运行结果. class A { static { System.out.print("1"); } public A() { System.out.print(& ...

  4. java静态类、静态方法、静态代码块,静态变量及实例方法,实例变量初始化顺序及内存管理,机制

    1.当一个类被第一次使用时,它需要被类加载器加载,而加载过程涉及以下两点: (1)在加载一个类时,如果它的父类还未被加载,那么其父类必须先被加载: (2)当类加载到内存之后,按照在代码中的出现顺序执行 ...

  5. Java接口以及匿名内部类,静态代码块

    接口 接口中只能定义public并且是final的公共静态常量,不允许定义变量. 抽象类可以定义抽象方法和非抽象方法,接口中只能定义公共的,抽象的实例方法. 接口只能由其他接口实现继承 子接口继承的目 ...

  6. 【Java面试题】16 静态代码块,main方法,构造代码块,构造方法

    public class HelloB extends HelloA{ public HelloB() { System.out.println("HelloB"); } { Sy ...

  7. Java面试题之类的静态代码块和静态属性等的加载顺序

    如以下面试题: /** * @author hjs * @date 2019/3/62:41 * @Dec */public class B { public static B t1 = new B( ...

  8. Java父类与子类中静态代码块 实例代码块 静态变量 实例变量 构造函数执行顺序

    实例化子类时,父类与子类中的静态代码块.实例代码块.静态变量.实例变量.构造函数的执行顺序是怎样的? 代码执行的优先级为: firest:静态部分 second:实例化过程 详细顺序为: 1.父类静态 ...

  9. Javascript的一种代码结构方式——插件式

    上几周一直在做公司的webos的前端代码的重构,之中对javascript的代码进行了重构(之前的代码耦合严重.拓展.修改起来比较困难),这里总结一下当中使用的一种代码结构——插件式(听起来怎么像独孤 ...

随机推荐

  1. C++构造函数

    一. 构造函数是干什么的class Counter{public:         // 类Counter的构造函数         // 特点:以类名作为函数名,无返回类型         Coun ...

  2. php字符串操作集锦

    web操作, 主要就是对字符文本信息进行处理, 所以, 字符串操作几乎占了很大一部分的php操作.包括 注意strstr 和 strtr的区别? 前者表示字符串查找返回字符串,后者表示字符串中字符替换 ...

  3. (转)CentOS下开机启动查看管理命令:chkconfig用法

    CentOS下开机启动查看管理命令:chkconfig用法   CentOS下开机启动查看管理的命令是:chkconfig   1. 开机启动列表查看: chkconfig --list     说明 ...

  4. KMP专题

    1.[HDU 3336]Count the string(KMP+dp) 题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是a.ab.aba.abab,在原字符串中出现的次数分别是2.2.1 ...

  5. Visual Studio EventHandler Delegate 和 EventArgs

    EventHandler代理 用来表示处理一个没有事件数据(event data)的事件(event)的 方法. 无论何时事件发生时,事件代理就被调用来触发以前事件驱动的其他事件(监听当前事件TCur ...

  6. 【Android】NavigationView头部点击监听事件

    AndroidStudio给出的模板里面只有列表点击事件,即实现OnNavigationItemSelectedListener中的onNavigationItemSelected方法,根据item的 ...

  7. Json.net日期格式化

    1. 全局设置,可以在App_Global中配置 JsonSerializerSettings setting = new JsonSerializerSettings(); JsonConvert. ...

  8. 数据库(Database)

    一.定义 1. 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,简单来说是本身可视为电子化的件柜--存储电子文件的处所,用户可以对文件中的数据进行新增.截取.更新.删除等操作.数 ...

  9. C#夯实基础之多线程一:初识多线程

    一. 烧水沏茶问题       在小学四年级有一个烧水沏茶问题,可以作为我们今天讨论话题的引子: 客人来了,要烧一壶茶,但是烧水需要5分钟,洗水壶需要1分钟,洗茶杯需要2分钟,接水需要1分钟,找茶叶需 ...

  10. PHP 查看安装信息

    1.运行PHP脚本,查看phpinfo函数的输出. 2.在系统环境变量Path中配好php.exe可执行文件的路径,命令管理器CMD中,执行`php.exe -i`查看. 3.在phpinfo()的输 ...