DependencyCheck+Jenkins扫描JAVA第三方依赖(CVE)漏洞_dependency-check

    }
}

/**
 * 拉取NVD的cve漏洞文件(json文件)
 * @param workspace       工作空间:默认当前jar的路径
 * @param nvdcachePath    存储漏洞库文件(json文件)的路径
 */
public void syncCveList(String workspace,String nvdcachePath) {
    //1、检查缓存目录是否存在
    File nvdcacheFile = new File(nvdcachePath);
    if(!nvdcacheFile.exists()){
        System.out.println("缓存目录不存在,创建!");
        nvdcacheFile.mkdirs();
    }

    String nistDataMirror = workspace + "/nist-data-mirror.jar";
    File nistDataMirrorFile = new File(nistDataMirror);
    if(!nistDataMirrorFile.exists()){
        System.out.println("nist-data-mirror.jar不存在,创建!");
        try{
            ClassPathResource classPathResource = new ClassPathResource("utils/nist-data-mirror.jar");
            InputStream inputStream = classPathResource.getStream();
            String destPath = workspace + "/nist-data-mirror.jar";

            FileUtils.copyInputStreamToFile(inputStream, new File(destPath));

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    //1、拉取NVD的cve漏洞文件
    String command = "java -jar "+workspace+"/nist-data-mirror.jar "+nvdcachePath;

    try {
        Process process = Runtime.getRuntime().exec(command);

        // 读取命令执行的输出
        InputStream inputStream = process.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        // 等待命令执行结束
        int exitCode = process.waitFor();
        System.out.println("命令执行结束,退出码:" + exitCode);

    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}





private void readFilesAll(String nvdcachePath){
    System.out.println("------------全量初始化------------");
    File nvdcacheFile = new File(nvdcachePath);
    File[] files = nvdcacheFile.listFiles((dir, name) -> name.toLowerCase().endsWith(".json"));
    for(File f : files){
        System.out.println(f.getAbsolutePath());
        parseJson(f.getAbsolutePath());
        System.out.println("");
    }
    System.out.println("------------全量初始化-完成------------");
}

private void updateRecentCve(String nvdcachePath){
    System.out.println("------------增量更新------------");
    File nvdcacheFile = new File(nvdcachePath);
    File[] files = nvdcacheFile.listFiles((dir, name) -> name.toLowerCase().endsWith(DateUtil.thisYear()+".json") || name.toLowerCase().endsWith("modified.json") || name.toLowerCase().endsWith("recent.json"));
    for(File f : files){
        System.out.println(f.getAbsolutePath());
        parseJson(f.getAbsolutePath());
        System.out.println("");
    }
    System.out.println("------------增量更新-完成------------");
}


private void parseJson(String filePath){
    try {
        String jsonStr = new String( Files.readAllBytes( Paths.get(filePath)));
        JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
        String CVE_Items = jsonObject.getStr("CVE_Items");
        List<CveObj> cveObjs = JSONUtil.toList(CVE_Items, CveObj.class);

        List<Cve> list = new ArrayList<>();
        // 对解析后的对象数组进行操作
        for (CveObj obj : cveObjs) {
            Cve cve = new Cve();
            cve.setId(obj.getCve().getCVE_data_meta().getID());
            try{
                cve.setSeverity(obj.getImpact().getBaseMetricV2().getSeverity()+"");
            }catch (Exception e){

            }
            cve.setDescription(JSON.toJSONString(obj.getCve().getDescription().getDescription_data()).replaceAll("'",""));
            cve.setPublishedDate(DateUtil.parseDate(obj.getPublishedDate()));
            cve.setLastModifiedDate(DateUtil.parseDate(obj.getLastModifiedDate()));

            list.add(cve);
        }

        this.saveOrUpdateBatch(list);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}


#### 


#### 2、获取cnnvd漏洞库


官网地址:[国家信息安全漏洞库 (cnnvd.org.cn)]( )")


CNNVD是我们国家的信息安全漏洞库,咱们这个漏洞库不仅仅收录了NVD的漏洞数据(CVE),还收录咱们国内的漏洞信息(CNNVD),也就是说同样一条漏洞信息,CNNVD的漏洞数据上面既有CVE漏洞编码,也有CNNVD编码,而且描述信息还是中文的。


获取方式:


![](https://img-blog.csdnimg.cn/184a1f92ab2a4a19a7595c82d3f7360f.png)


![](https://img-blog.csdnimg.cn/b61b254975504720b1b93530faabd6e6.png)


#### 3、转换为自定义漏洞库


CNNVD漏洞数据库下载后是xml格式的文件,我们需要写代码将xml里面我们需要的数据提取出来,保存在数据库表里面



@GetMapping
public void insertCnnvd(int type) throws JAXBException {

    if(type==0){
        for(int i=1999;i<=2023;i++){
            System.out.println("-------->开始读取"+i+"年数据:");
            List<Cnnvd> nvdList = parseXml(i);
            System.out.println("-------->成功读取"+i+"年数据:"+nvdList.size());
            cnnvdService.saveOrUpdateBatch(nvdList);
            System.out.println("-------->成功写入数据:"+nvdList.size());
            System.out.println("");
            System.out.println("");
        }
    }else{
        System.out.println("-------->开始读取"+DateUtil.thisYear()+"年数据:");
        List<Cnnvd> cnnvdList = parseXml(2023);
        System.out.println("-------->成功读取"+DateUtil.thisYear()+"年数据:"+cnnvdList.size());
        cnnvdService.saveOrUpdateBatch(cnnvdList);
        System.out.println("-------->成功写入数据:"+cnnvdList.size());
    }
}

public List<Cnnvd> parseXml(int fileName) throws JAXBException {
    //可能的问题:[org.xml.sax.SAXParseException; lineNumber: 2292; columnNumber: 191; 元素类型 "use" 必须由匹配的结束标记 "</use>" 终止。]] with root cause
    //解决的方案:在内网的签名添加字符串:<![CDATA[             在内网的结尾添加字符串:]]>
    InputStream stream = this.getClass().getClassLoader().getResourceAsStream("cnnvd/"+fileName+".xml");

    JAXBContext jaxbContext = JAXBContext.newInstance(VulnerabilityList.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    VulnerabilityList vulnerabilityList = (VulnerabilityList) jaxbUnmarshaller.unmarshal(stream);
    List<Cnnvd> vulnerabilities = vulnerabilityList.vulnerabilities;

    return vulnerabilities;
}


@Data
@XmlRootElement(name = “entry”)
@XmlAccessorType(XmlAccessType.FIELD)
public class Cnnvd implements Serializable {
@TableId(type = IdType.INPUT)
@XmlElement(name = “vuln-id”)
public String id;
@XmlElement(name = “name”)
public String name;
@XmlElement(name = “published”)
public String published;
@XmlElement(name = “modified”)
public String modified;
@XmlElement(name = “source”)
public String source;
@XmlElement(name = “severity”)
public String severity;
@XmlElement(name = “vuln-type”)
public String vulnType;
@XmlElement(name = “vuln-descript”)
public String description;
@XmlElement(name = “cve-id”)
public String cveId;
@XmlElement(name = “bugtraq-id”)
public String bugtraqId;
@XmlElement(name = “vuln-solution”)
public String solution;
}


![](https://img-blog.csdnimg.cn/85d0ada2fbfe42089a6e98121e4aa676.png)


### 三、使用DependencyCheck扫描



/root/dependency-check/bin/dependency-check.sh --project “test-服务端第三方依赖CVE漏洞扫描报告” --scan “**/*.jar” -n -f JSON -o “/var/www/html/test-服务端第三方依赖CVE漏洞扫描报告.json”


### 四、输出自定义扫描报告


#### 1、使用pot-tl自定义word模板


![](https://img-blog.csdnimg.cn/72645e31ae73407ebd6685232e0df991.png)


#### 2、解析json生成word报告


将上面扫描的“test-服务端第三方依赖CVE漏洞扫描报告.json”数据解析出来,填充到我们的自定义模板中,最终生成我们的word报告。



/**
* 根据json报告解析漏洞信息并入库:方便后续直接构建word和excel
* @param name 报告名称
* @param sourePath json报告路径
* @param reportPath word报告路径
* @param gitHttpUrl git的http地址
* @param gitBranch git分支
* @return
* @throws IOException
*/
@GetMapping
public String vulScanReport(String name, String sourePath,String reportPath,String gitHttpUrl,String gitBranch) throws IOException {
//解析扫描的json报告,并将数据写入数据库
int num = cnnvdService.analysisCveJsonv2(name,sourePath, gitHttpUrl, gitBranch);
if(num>0){
//读取扫描的漏洞数据,填充自定义模板,生成word报告
String fileName = cnnvdService.createWord(name,reportPath,gitHttpUrl,gitBranch);
return fileName;
}else{
return “”;
}
}



package com.yunhuang.autosafe.common.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.util.PoitlIOUtils;
import com.yunhuang.autosafe.common.entity.;
import com.yunhuang.autosafe.common.mapper.CnnvdMapper;
import com.yunhuang.autosafe.common.service.
;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.;
import java.util.
;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class CnnvdServiceImpl extends ServiceImpl<CnnvdMapper, Cnnvd> implements CnnvdService {

@Autowired
private NvdMyService nvdMyService;
@Autowired
private CveService cveService;
@Autowired
private ScanDependencieService dependencieService;
@Autowired
private ScanVulnerabilitieService vulnerabilitieService;
@Resource
private RedisTemplate redisTemplate;

private final static String REDIS_NVD_KEY = "cve_data";

/**
 * 根据json报告解析漏洞信息并入库:方便后续直接构建word和excel
 * @param name   报告名称
 * @param sourePath   json报告路径
 * @param gitHttpUrl  git的http地址
 * @param gitBranch   git分支
 * @return
 * @throws IOException
 */
@Override
public Integer analysisCveJsonv2(String name, String sourePath, String gitHttpUrl, String gitBranch) throws IOException {
    //数据库统一记录时间
    Date createTime = new Date();
    String jsonStr = readFileContent(sourePath);
    JSONObject jsonObject = JSONUtil.parseObj(jsonStr);

    //依赖
    String dependencies = jsonObject.getStr("dependencies");
    JSONArray array = JSONUtil.parseArray(dependencies);

    //依赖下的漏洞
    List<ScanDependencie> dependencieList = JSONUtil.toList(array, ScanDependencie.class);
    System.out.println("--------------->依赖项总数:"+dependencieList.size());

    //漏洞详情列表
    List<ScanDependencie> dependencieVulList = new ArrayList<>();
    //漏洞清单汇总
    List<ScanVulnerabilitie> vulnerabilitiesAll = new ArrayList<>();
    //扫描到的漏洞清单
    List<String> cveScanList = new ArrayList<>();


    int i = 1;

    //遍历依赖:构建导出数据
    for(ScanDependencie d :dependencieList){
        if(d.getVulnerabilities()==null || d.getVulnerabilities().size()==0) continue;

        int pindex = i++;
        String depId = UUID.randomUUID().toString().replaceAll("-","");
        d.setId(depId);
        d.setName(name);
        d.setSortIndex(pindex);
        d.setFileName(d.getFileName().replaceAll(" ",""));
        d.setGitHttpUrl(gitHttpUrl);
        d.setGitBranch(gitBranch);
        d.setScanDate(createTime);
        if(StringUtils.isNotBlank(d.getDescription())) d.setDescription(d.getDescription().trim());

        int m = 1;
        //遍历依赖下的漏洞
        List<ScanVulnerabilitie> vulnerabilities = d.getVulnerabilities();
        for(ScanVulnerabilitie vul : vulnerabilities){
            if(vul.getName().indexOf("CVE")==-1) continue;

            //添加到扫描漏洞清单
            cveScanList.add(vul.getName());

            int index = m++;
            vul.setDependencieId(depId);
            vul.setSortIndex(index);
            vul.setSortIndexStr(pindex+"."+index);
            vul.setScanDate(createTime);

            vulnerabilitiesAll.add(vul);
        }

        dependencieVulList.add(d);
    }


    //清除之前的数据
    QueryWrapper<ScanDependencie> wrapper = new QueryWrapper<>();
    wrapper.eq("git_http_url",gitHttpUrl);
    List<ScanDependencie> oldList = dependencieService.list(wrapper);
    List<String> depIds = oldList.stream().map(ScanDependencie::getId).collect(Collectors.toList());

    if(depIds.size()>0){
        QueryWrapper<ScanVulnerabilitie> wrapper2 = new QueryWrapper<>();
        wrapper2.in("dependencie_id",depIds);
        vulnerabilitieService.remove(wrapper2);
    }
    dependencieService.remove(wrapper);

    //保存扫描到的依赖数据:dependencieVulList
    dependencieService.saveBatch(dependencieVulList);
    //保存扫描到的依赖数据:vulnerabilitiesAll
    vulnerabilitieService.saveBatch(vulnerabilitiesAll);
    System.out.println("--------------->有漏洞的依赖项:"+dependencieVulList.size());
    System.out.println("--------------->漏洞总数:"+vulnerabilitiesAll.size());
    System.out.println("");
    return vulnerabilitiesAll.size();
}

@Override
public String createWord(String name, String reportPath, String gitHttpUrl, String gitBranch) throws IOException {

    //所有的有漏洞的依赖
    List<ScanDependencie> dependencieList = new ArrayList<>();
    //所有的漏洞清单
    List<ScanVulnerabilitie> vulList = new ArrayList<>();
    //漏洞清单分组
    Map<String, List<ScanVulnerabilitie>> listMap = new HashMap<>();
    //漏洞编码
    List<String> cveIds = new ArrayList<>();
    //对应的cnnvd信息(中文解释)
    Map<String, Cnnvd> cnnvdMap = new HashMap<>();
    //nvd漏洞原始信息(英文内容)
    Map<String, Cve> cveMap = new HashMap<>();

    QueryWrapper<ScanDependencie> wrapper1 = new QueryWrapper();
    wrapper1.eq("name",name).eq("git_http_url",gitHttpUrl).orderByAsc("sort_index");
    dependencieList = dependencieService.list(wrapper1);

    List<String> depIds = dependencieList.stream().map(ScanDependencie::getId).collect(Collectors.toList());
    if(depIds==null || depIds.size()==0) return null;

    QueryWrapper<ScanVulnerabilitie> wrapper2 = new QueryWrapper<>();
    wrapper2.in("dependencie_id",depIds).orderByAsc("id");
    vulList = vulnerabilitieService.list(wrapper2);
    //漏洞根据依赖id分组
    listMap = vulList.stream().collect(Collectors.groupingBy(ScanVulnerabilitie::getDependencieId));

    cveIds = vulList.stream().map(ScanVulnerabilitie::getName).distinct().collect(Collectors.toList());
    //根据漏洞编码查询cnnvd漏洞库

最后

image.png

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
vulList = vulnerabilitieService.list(wrapper2);
//漏洞根据依赖id分组
listMap = vulList.stream().collect(Collectors.groupingBy(ScanVulnerabilitie::getDependencieId));

    cveIds = vulList.stream().map(ScanVulnerabilitie::getName).distinct().collect(Collectors.toList());
    //根据漏洞编码查询cnnvd漏洞库

最后

[外链图片转存中…(img-03GGmm8Y-1725622303996)]

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值