<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          利用Sonatype API實(shí)現(xiàn)依賴檢測工具

          共 17414字,需瀏覽 35分鐘

           ·

          2023-05-06 20:36

          背景

          由于畢設(shè)答辯時(shí)間提前,導(dǎo)致迫不得已砍掉部分功能,而個(gè)人感覺功能有點(diǎn)少故添加了個(gè)依賴檢測功能,大體原理利用Maven API解析提取上傳的Pom文件中的依賴項(xiàng),然后借助Sonatype進(jìn)行安全檢測。


          依賴項(xiàng)提取

          其實(shí)這里實(shí)現(xiàn)方式多種,模仿XmlDecoder的方式自定義DocumentHandler雖然可以(Tomcat內(nèi)部解析web.xml就是這種方式)不過對于部分把版本號以變量形式約束定義在Properties標(biāo)簽的情況處理比較麻煩,故采用Maven API,它可以直接提取properties中的標(biāo)簽值等。

          0604eda2ba7984d1afb650eabafed0f6.webp

          依賴

                
                  
                    <dependency>
                  
                
                
                    <groupId>org.apache.maven</groupId>
                
                
                    <artifactId>maven-model-builder</artifactId>
                
                
                    <version>3.8.1</version>
                
                
                  
                    </dependency>
                  
                
                
                  
                    <dependency>
                  
                
                
                    <groupId>org.apache.maven</groupId>
                
                
                    <artifactId>maven-model</artifactId>
                
                
                     <version>3.8.1</version>
                
                
                  
                    </dependency>
                  
                
              

          代碼實(shí)現(xiàn)

                
                  import java.io.File;
                
                
                  import java.io.FileReader;
                
                
                  import java.io.StringReader;
                
                
                  import java.io.StringWriter;
                
                
                  import java.util.ArrayList;
                
                
                  import java.util.List;
                
                
                  import java.util.Properties;
                
                
                  import java.util.regex.Matcher;
                
                
                  import java.util.regex.Pattern;
                
                
                  
                    
          import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory;
          import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Model; import org.apache.maven.model.io.DefaultModelWriter; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList;
          public class PomParser { ????//?參數(shù):Pom文件絕對路徑 public static List<Dependency> parse(String pomPath) throws Exception { List<Dependency> result = new ArrayList<>(); MavenXpp3Reader reader = new MavenXpp3Reader(); Model model = reader.read(new FileReader(pomPath));
          Properties properties = model.getProperties(); // 獲取所有屬性 // 將model對象轉(zhuǎn)為xml字符串 DefaultModelWriter writer = new DefaultModelWriter(); StringWriter stringWriter = new StringWriter(); writer.write(stringWriter, null, model);
          String xmlString = stringWriter.toString();
          // 合并Dependencies和DependencyManagement List<org.apache.maven.model.Dependency> allDependencies=model.getDependencies(); DependencyManagement dependencyManagement = model.getDependencyManagement(); if (dependencyManagement!=null && dependencyManagement.getDependencies().size()>0){ allDependencies.addAll(dependencyManagement.getDependencies()); } for (org.apache.maven.model.Dependency dependency : allDependencies) { // 遍歷每個(gè)依賴對象 String version = dependency.getVersion();
          if (version!=null && version.startsWith("${") && version.endsWith("}")) { // 如果版本號以${}包裹,則需要進(jìn)行替換 String propertyName = version.substring(2, version.length() - 1); String propertyValue = properties.getProperty(propertyName);
          if (propertyValue == null) { // 如果屬性不存在,拋出異常 throw new IllegalArgumentException("Property not found: " + propertyName); } dependency.setVersion(propertyValue); } }
          for (org.apache.maven.model.Dependency dependency : allDependencies) { result.add(new Dependency(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())); } return result; } }


          //?Denpendency結(jié)構(gòu)體 public static class Dependency { private final String groupId; private final String artifactId; private final String version;
          public Dependency(String groupId, String artifactId, String version) { this.groupId = groupId; this.artifactId = artifactId; this.version = version; }
          public String getGroupId() { return groupId; }
          public String getArtifactId() { return artifactId; }
          public String getVersion() { return version; } }



          Https問題

          由于Sonatype的API為HTTPS,導(dǎo)致測試時(shí)候獲取不到數(shù)據(jù),查閱網(wǎng)上方案得以解決

                
                  package com.VulnScanner.DpendCheck;
                
                
                  
                    

          import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import org.apache.http.util.EntityUtils;
          import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate;
          public class HttpsUtils { static CloseableHttpClient httpClient; static CloseableHttpResponse httpResponse;
          public static CloseableHttpClient createSSLClientDefault() { try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { // 信任所有 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); return HttpClients.custom().setSSLSocketFactory(sslsf).build(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } return HttpClients.createDefault();
          }
          /** * 發(fā)送https請求 * * @param content * @throws Exception */ public static String send(String content, String url) { try { HttpPost request = new HttpPost(url); StringEntity entity = new StringEntity(content, "UTF-8"); entity.setContentEncoding("UTF-8"); entity.setContentType("application/json"); request.setEntity(entity); request.addHeader("Connection", "Keep-Alive"); request.addHeader("accept", "application/json"); request.addHeader("Content-Type", "application/json"); httpClient = HttpsUtils.createSSLClientDefault(); httpResponse = httpClient.execute(request); HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity != null) { String jsObject = EntityUtils.toString(httpEntity, "UTF-8"); return jsObject; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } finally { try { httpResponse.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }



          調(diào)用API檢測

          Sonatype API:https://ossindex.sonatype.org/rest

          4d3cb9aab07d3f56f893c92764e7fee0.webp

          可以看到參數(shù)主要是這個(gè)?coordinates?字段,關(guān)于它的格式定義(https://ossindex.sonatype.org/doc/coordinates)

          aafc523109d4cd8b641517443a21b5b1.webp

          如果是檢測Java項(xiàng)目則格式如下

                
                  maven:groupId/artifactId@Version
                
              

          是以,我們可以進(jìn)行組合實(shí)現(xiàn)檢測依賴文件中的依賴項(xiàng)安全。

          3ff840105d1077a1b2f56fc699a62abb.webp

          c1c3844c65be0bb22ddcf27d3f6a843e.webp

                
                  public class Checker {
                
                
                      private static final String API_BASE_URL = "https://ossindex.sonatype.org/api/v3";
                
                
                  
                    

          public List<ScanResult> getAllVulns(String filePath) throws Exception { List<ScanResult> scanResults=new ArrayList<ScanResult>(); try { List<PomParser.Dependency> dependencies = PomParser.parse(filePath); for (PomParser.Dependency dependency:dependencies){ scanResults.addAll(scanDependencies(dependency.getGroupId(),dependency.getArtifactId(),dependency.getVersion())); } }catch (Exception e){}
          return scanResults; }



          /** * 掃描指定 Maven 項(xiàng)目的所有依賴項(xiàng),并返回包含 CVE 信息的掃描結(jié)果。 * * @param groupId Maven 項(xiàng)目的 Group ID * @param artifactId Maven 項(xiàng)目的 Artifact ID * @param version Maven 項(xiàng)目的版本號 * @return 包含 CVE 信息的掃描結(jié)果列表 */ public List<ScanResult> scanDependencies(String groupId, String artifactId, String version) throws IOException, JSONException { // 處理 CVE 數(shù)據(jù)并生成掃描結(jié)果 List<ScanResult> results = new ArrayList<>(); try{ // 構(gòu)造 API 請求 URL String url = API_BASE_URL + "/component-report/"; String content="{ \"coordinates\":[\"maven:"+groupId+"/"+artifactId+"@"+version+"\"]}"; // 解析 JSON 響應(yīng) String data = HttpsUtils.send(content, url); int start = data.indexOf("[{"); data=data.substring(start+1,data.length()-1); JSONObject jsonResponse = new JSONObject(data); JSONArray vulnerabilities = jsonResponse.optJSONArray("vulnerabilities");
          if (vulnerabilities != null) { for (int i = 0; i < vulnerabilities.length(); i++) { JSONObject vuln = vulnerabilities.getJSONObject(i); String cveId = vuln.optString("cve"); String description = vuln.optString("description"); results.add(new ScanResult(cveId, description,groupId,artifactId,version)); } } }catch (Exception e){
          } return results; ????} }


          //?ScanResult結(jié)構(gòu)體(自行生成Getter/Setter) public class ScanResult { private String cveId; private String description; private String groupId; private String artifactId; private String version;
          public ScanResult(String cveId, String description,String groupId,String artifactId,String version) { this.cveId = cveId; this.description = description; this.groupId=groupId; this.artifactId=artifactId; this.version=version; ????} }

          需要注意的是這里有點(diǎn)坑,那就獲取到的數(shù)據(jù)包含了響應(yīng)頭數(shù)據(jù),故這里利用響應(yīng)體結(jié)構(gòu)特性進(jìn)行了較為暴力的處理,當(dāng)然也可以用其他方式實(shí)現(xiàn),這里個(gè)人偷懶。

                
                  int start = data.indexOf("[{");
                
                
                  data=data.substring(start+1,data.length()-1);
                
              



          效果

          以下為個(gè)人實(shí)現(xiàn)效果,這里沒有給出我控制器這邊代碼,可自行琢磨封裝使用。

          fb8b899c52dfc2744bee088444b4b60f.webp



          結(jié)語

          注意一下的是Sonatype并非只能檢測Java依賴項(xiàng)安全,它支持多種語言的依賴檢測,只不過這里以Java為例。

          a48ae6bd6a4fe7879563ae9276e95cf2.webp


          瀏覽 59
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩激情网 | 亚洲一线视频网站播放 | 人人干人人操人人 | 欧美深夜福利 | 天天干天天操天天插 |