摘要:靜态掃描工具融入在DevSecOps的開發過程中,對提高産品的整體的安全水準發揮着重要的作用。為了擷取安全檢查能力覆寫的最大化,開發團隊通常會引入多個安全掃描工具。為了降低各種分析工具的結果彙總到通用工作流程中的成本和複雜性, 業界開始采用靜态分析結果交換格式(SARIF)。
1. 引言
從2012年Gartner的研究報告“DevOpsSec: Creating the Agile Triangle”提出了DevSecOps的概念, 到目前DevSecOps已經成為建構企業級研發安全的重要模式。 DevSecOps模式中有些重要的原則:安全左移、預設安全、運作時安全、安全服務自動化/自助化、基礎設施即代碼(IaC)、持續內建和傳遞,以及需要組織和文化建設。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5ydwIzNfljZ0gDM4QGO3MTYwQDO0gzMkRzYjJ2Y1QDOhZTNwIWNtIjdvwFM48CXt92YucWbphmeuIzYpB3Lc9CX6MHc0RHaiojIsJye.jpg)
在DevSecOps的過程中,最重要的一環就是安全工具能夠快速內建到自動化平台,保證平台的持續內建和傳遞,進而提高産品的整體的安全水準。 在整個研發過程中靜态安全檢查工具是保證代碼安全的重要手段,每個安全檢查工具因為技術實作上的差異,對不同的安全缺陷有着不同的檢查能力,是以稍微大型一些的開發團隊, 在開發的時候會引入多個安全掃描工具,以擷取安全檢查能力覆寫的最大化。 但多工具的內建, 就會對程式員或平台的內建會帶來以下問題:
- 對于開發人員
- 在使用IDE的時候, 缺少一個通用的檢查工具結果接口和互動接口;
- 需要檢視多個檢查工具的結果;
- 對于內建平台
- 需要學習每個工具的輸出掃描格式;
- 在掃描報告轉入到缺陷跟蹤系統的時候, 缺少一個通用的缺陷轉換程式;
- 缺少一個通用掃描結果度量方式。
為了解決這些的問題,最初由微軟、Micro focus等幾家靜态分析軟體公司提出了:靜态分析結果交換格式(Static Analysis Results Interchange Format (SARIF))。
2. 結構化資訊标準促進組織(OASIS)
結構化資訊标準促進組織(Organization for the Advancement of Structured Information Standards (OASIS))是一個非營利性的國際财團,推動全球資訊社會制定、融合和采用開放标準。OASIS 促進行業共識,并制定網絡安全、隐私、雲計算、物網、智能電網和其他領域的全球标準。OASIS 開放标準具有降低成本、刺激創新、開拓全球市場和保護自由選擇技術的權利的潛力。
OASIS 成員廣泛代表公共和私營部門技術上司者、使用者和影響者的市場。自1993年成立開始,OASIS已經發展成為了由來自100多個國家的600多家組織、企業,參與人數超過5000人的國際化組織。相比其他組織,OASIS形成了更多的Web服務标準的同時也提出了面向安全、電子商務的标準,同時在針對公衆領域和特定應用市場的标準化方面也付出很多的努力。
OASIS以其管理透明化及工作流程化而著稱。OASIS成員自己設定技術議程,并通過簡單的工作流程促進産業達成一緻以及統一不同觀點。OASIS的全部工作将是通過公開投票的方式認可,管理層具有責任心并且不受其他因素制約。OASIS理事會和技術顧問委員會的成員都由民主選舉産生,任期2年。OASIS的上司層是由于個人能力而非資金資助、企業背景或特别任命而産生的。
OASIS現在擁有最受人們廣泛接受的XML以及Web服務标準2個資訊入口,Cover Pages和http://XML.org。OASIS的成員分會包括CGM Open、DCML、LegalXML、PKI和UDDI。
OASIS于1993年最初以SGML開放組織名義成立。它最初是代表使用者和産品提供商緻力于推動産品互操作性架構的開發以及支援标準廣義标記語言(Standard Generalized Markup Language)。1998年,組織的名稱正式更換為OASIS開放組織,以表示其在技術領域的工作已經擴充到可擴充标記語言 (XML)及相關标準以外的範圍。
- OASIS 主要技術成員
-
OASIS成立SARIF技術委員會
因為靜态分析工具在安全保障中的重要地位,越來越多的靜态分析工具的主要廠商CA Technologies, Cryptsoft, FireEye, GrammaTech, Hewlett Packard Enterprise (HPE), Micro Focus, Microsoft, New Context, Phantom, RIPS, SWAMP, Synopsys, U.S. DHS, U.S. NIST等等都在推進靜态分析工具的通用資料格式的标準。 2017年10月12日, OASIS成立了SARIF技術委員會為靜态分析制定國際互操作性标準。SARIF技術委員會彙集了主要軟體公司、網絡安全提供商、政府、安全協調專家、程式員和顧問,就一種資料格式達成一緻,該格式将由整個行業的工具解析。目标是通過聚合來自多個工具的資料,使軟體開發人員更容易評估其程式的品質和安全性。
在接下來的2018年,SARIF就獲得了OASIS的年度Open Standards Cup的傑出新計劃(Outstanding New Initiative)。
3. SARIF規範簡介
-
SARIF的目标:
- 全面捕獲常用靜态分析工具生成的資料範圍;
- 分析工具直接輸出的一種有用的格式,并且是可以将任何分析工具的輸出轉換成的有效交換格式;
- 适用于與分析結果管理相關的各種方案,并且可擴充用于新方案;
- 降低将各種分析工具的結果彙總到通用工作流程中的成本和複雜性;
- 捕獲有助于評估項目是否符合公司政策或符合認證标準的資訊;
- 采用廣泛使用的序列化格式,可以使用現成的工具進行解析;
- 表示各種程式設計工件的分析結果,包括源代碼和目标代碼。
-
規範描述的範圍:
- 單個日志檔案中包含多個不同分析工具的運作結果;
- 執行每次運作的分析工具,包括:
- 工具名稱
- 工具版本
- 分析工具的調用,包括:
- 指令行
- 開始時間和結束時間
- 被分析的檔案,包括:
- Uniform Resource Identifier(URI)
- Multipurpose Internet Mail Extensions(MIME 類型)
- 嵌套檔案,例如壓縮存檔中包含的檔案,例如ZIP檔案。
- 執行的分析規則
- 有關産生的每個分析結果的資訊,包括:
- 結果的位置
- 違反的規則
- 違規的嚴重性
- 代碼中與結果相關的執行路徑
- 相對于結果的調用堆棧
- 該問題的可能修補程式
- 分析工具産生的通知,包括:
- 進度消息
- 配置資訊
-
不包含在規範範圍
- 用于通路、操縱或管理SARIF檔案中包含的資訊的任何應用程式程式設計接口(API)的定義或實作;
- 用于檢視或以其他方式與SARIF檔案中包含的資訊進行互動的任何體驗的定義或實作。
目前這個版本有200多頁。按照由淺入深的方式,介紹将分為基礎和進階兩個部分。此篇為基礎部分,将完成規範中的基本概念和初步使用的介紹。 後續的進階部分,将完成深層次使用者的需求實作。
4. SARIF基礎
SARIF檔案是以一種以面向對象(Object Model)的方式構成json檔案。 這樣的設計便于工具通過對象的方式對應到json的各個組成部分。 SARIF 的json檔案格式通過格式檔案sarif-2.1.0-rtm.4.json定義, 目前版本是2.1.0。
我們先來看一個ESLint掃描結果的一個SARIF的例子。
代碼(simple-example.js):
var x = 42
ESLint 檢查指令:
eslint --format sarif simple-example.js --output-file simple-example.sarif
SARIF格式輸出的檢查結果
{
"version": "2.1.0",
"$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.4",
"runs": [
{
"tool": {
"driver": {
"name": "ESLint",
"informationUri": "https://eslint.org",
"rules": [
{
"id": "no-unused-vars",
"shortDescription": {
"text": "disallow unused variables"
},
"helpUri": "https://eslint.org/docs/rules/no-unused-vars",
"properties": {
"category": "Variables"
}
}
]
}
},
"artifacts": [
{
"location": {
"uri": "file:///C:/dev/sarif/sarif-tutorials/samples/Introduction/simple-example.js"
}
}
],
"results": [
{
"level": "error",
"message": {
"text": "'x' is assigned a value but never used."
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "file:///C:/dev/sarif/sarif-tutorials/samples/Introduction/simple-example.js",
"index": 0
},
"region": {
"startLine": 1,
"startColumn": 5
}
}
}
],
"ruleId": "no-unused-vars",
"ruleIndex": 0
}
]
}
]
}
直接看這個報告,還是很容易直接讀懂的。
4.1. SARIF schema的基本組成
下圖為SARIF的schema定義檔案的視圖:
從SARIF的schema的結構。 我們可以看到:
- 第7行(“type”: “object”,), 定義了一個節點名為類型的對象;
- 第8-45行,定義了這個對象的屬性包(“properties”)中有的5個子節點:$schema,version,runs,inlineExternalProperties,properties;
- 第47行, "required"節點,定義了這個對象的屬性節點中必須有的節點:version, runs;
- 第16-19行,給出了節點version的定義,其中17行節點description給出了這個節點version的描述;18行告訴了version的取值是個枚舉值,并且隻有一個可能的取值:2.1.0;
- 第21-29行,給出了節點runs的定義:
- 22行,description給出了這個節點的描述:一組運作結果;
- 23行,給出了這個節點的類型是數組(array),每一個運作結果就是這個數組中的一個結果;
- 24行,數組最小可以為0;也就是說可以沒有運作結果;
- 25行,結果的内容可以不唯一;
- 26行,每個數組元素的組成定義;
- 27行,數組元素的定義參考定義組節點definitions下的run的定義;
- 第41-44行,定義了這個對象的擴充屬性通過key,value的方式定義,具體的定義參考定義組節點definitions下的propertyBag的定義;
- 第49-3369(到結束)行,通過定義組節點definitions定義了52個基礎對象:address, artifact, artifactChange等,包括前面提到的run和propertyBag;
- SARIF就是通過這52個基礎對象,以及這些基礎對象的組合,并通過屬性包的key,value方式完成各種擴充資訊的定義, 進而形成了了一個适應各種靜态掃描分析工具報告的規範化;
4.2. SARIF對象定義(definitions)的基本規則
- 通過定義組節點definitions定義了52個基礎對象, 完成對象的定義的描述;
- 通過基本類型(type)定義每個屬性的類型;類型有:object, string,number, integer, boolean, array;對于array類型,後面需要跟items,來說明數組元素的資訊;
- 通過enum來枚舉屬性的值;例如: “enum”: [ “none”, “note”, “warning”, “error” ]
- 通過參考引用的方式完成相似類型的定義描述,避免了反複定義和定義的統一性,歸一性;例如:"$ref": “#/definitions/propertyBag”,表明該對象是參考定義組definitions下的propertyBag;
- 通過anyOf,required屬性定義對象中必須存在的屬性, 預設情況下,屬性不是必須的;
- 每一個對象都有一個properties屬性,通過屬性包的方式中key,value的方式完成對象擴充資訊定義的需要;
4.3. 定義舉例:消息(message)
- message在definitions中的定義:
"message": {
"description": "Encapsulates a message intended to be read by the end user.",
"type": "object",
"additionalProperties": false,
"properties": {
"text": {
"description": "A plain text message string.",
"type": "string"
},
"markdown": {
"description": "A Markdown message string.",
"type": "string"
},
"id": {
"description": "The identifier for this message.",
"type": "string"
},
"arguments": {
"description": "An array of strings to substitute into the message string.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"type": "string"
}
},
"properties": {
"description": "Key/value pairs that provide additional information about the message.",
"$ref": "#/definitions/propertyBag"
}
},
"anyOf": [
{ "required": [ "text" ] },
{ "required": [ "id" ] }
]
},
- description:對象的描述,用于封裝提供給使用者讀取的資訊;
- type: 對象;
- additionalProperties: 沒有輔助屬性資訊;
- properties:屬性集
- text:字元型,純文字字元串;
- markdown:字元型,markdown格式的字元串;
- id: 字元型,資訊的編号;
- arguments:字元串數組,用于替代message中的參數;
- properties:屬性集,通過key,value的方式擴充,參考定義組節點definitions下的propertyBag的定義;
- anyOf: 至少text 或 id 必須;其他屬性可選;
- 例子:
{
"message": {
"text": "'x' is assigned a value but never used."
}
}
5. SARIF報告的基本結構
5.1. 工具的定義(runs.tool.driver)
在掃描結果(runs)的定義中,tool節點是必須的,tool中driver是必須的,而driver中也隻有name是必須的,也就是說除了工具的名字是必須的,其他的屬性都是可選的。這也可以看出來,這個報告也可以做的非常的簡單,隻強制定義了一些非常必要的資訊。
- 運作結果組runs下的數組元素是參考定義組節點definitions下的run的定義;
- run屬性中的必須節點tool的定義是參考定義組節點definitions下的tool的定義;
- tool屬性中的必須節點driver的定義是參考定義組節點definitions下的toolComponent的定義;工具可以通過tool.driver 完成工具的各種基本資訊的定義;
- 對與工具的其他擴充元件(例如各種插件),可以通過tool.extensions完成定義,extensions是個數組類型,每個數組元素也是參考定義組節點definitions下的toolComponent的定義;
- 通過toolComponent,可以定義:
- 元件的基本資訊:
- 工具的名字(name),全名(fullName),版本(version),傳遞時間(releaseDateUtc);
- 元件所屬組織(organization),産品(product)和産品組(productSuite)資訊;
- 下載下傳位址(downloadUri),元件的參考資訊位址(informationUri);
- 元件的語言資訊:
- 使用語言(language);
- 多語言支援(globalMessageStrings);
- 本地化的資訊版本(localizedDataSemanticVersion);
- 關聯元件(associatedComponent);
- 元件的擴充資訊通過屬性包(properties)實作;
- 舉例:
"tool": {
"driver": {
"name": "ESLint",
"informationUri": "https://eslint.org",
}
},
5.2. 規則的定義(run.tool.driver.rules)
定義組節點definitions下的toolComponent中定義了rules節點。規則(rules)的定義是一個數組類型,每個規則的定義參考定義組節點definitions下的reportingDescriptor的定義,reportingDescriptor定義中:
- id 是必須的;
- 名字(name),guid(guid),長、短描述(shortDescription,fullDescription);
- 以前版本的相關資訊(deprecatedIds,deprecatedGuids,deprecatedNames);
- 規則的資訊(messageStrings),通過參考定義組節點definitions下的multiformatMessageString實作多語言支援;
- 規則的預設配置(defaultConfiguration);
- 規則的幫助資訊(helpUri,help), help通過參考定義組節點definitions下的multiformatMessageString實作多語言支援;
- 規則的擴充資訊通過屬性包(properties)實作;
"rules": [
{
"id": "no-unused-vars",
"shortDescription": {
"text": "disallow unused variables"
},
"helpUri": "https://eslint.org/docs/rules/no-unused-vars",
"properties": {
"category": "Variables"
}
}
]
5.3. 掃描内容的定義(run.artifacts)
定義組節點definitions下的run的下面有一個artifacts節點,artifacts是一個數組節點類型,每個數組元素參考定義組節點definitions下的artifact的定義。artifact包括:
- 描述(description);
- 位置資訊(location,parentIndex,offset);
- 内容資訊(contents,encoding,sourceLanguage,length);
- 改動資訊(hashes,lastModifiedTimeUtc);
- 擴充資訊(properties);
5.4. 掃描結果的定義(run.results)
定義組節點definitions下的run的下面有一個results節點,results是一個數組節點類型,每個數組元素參考定義組節點definitions下的result的定義。result包括:
- result節點下面隻有message是必選項,以確定結果有資訊輸出;
- 規則資訊:
- ruleId:規則的編号;
- ruleIndex: 規則的索引編号;
- rule: rule的定義參考定義組節點definitions下的reportingDescriptor的定義, 同規則的那部分;
- 缺陷類型:
- kind: {“notApplicable”, “pass”, “fail”, “review”, “open”, “informational”};
- level: {“none”, “note”, “warning”, “error”};
- rank: -1.0 <= rank <= 100.0;
- 缺陷位置:
- analysisTarget:參考定義組節點definitions下的artifact的定義;
- locations:是一個數組節點類型,每個數組元素參考定義組節點definitions下的location的定義。location包括:
- id: 在一個缺陷内location的唯一值;
- physicalLocation: 參考定義組節點definitions下的physicalLocation的定義。 physicalLocation包括:
- address:通過位址域的相對或者絕對偏移量來表示問題位置;
- artifactLocation:檔案的方式表示缺陷的位置;
- address 和 artifactLocation 是最少二選一的;
- region: 指定檔案的區域;有以下三種方式:
- 通過代碼行、列:startLine, startColumn, endLine, endColumn 來指定區域;
- 通過字元偏移量:charOffset,charLength來指定區域;
- 通過位元組偏移量:byteOffset, byteLength來指定區域;可以用于二進制位置定位;
- snippet:代碼片段, 參考定義組節點definitions下的artifactContent定義;
- 缺陷辨別:
- guid: 缺陷的辨別GUID;
- correlationGuid:根據缺陷特征生成的GUID;
- occurrenceCount:同樣缺陷特征在本次掃描中出現的次數;
- partialFingerprints: 部分缺陷特征;
- fingerprints: 缺陷特征指紋;
- 缺陷追蹤資訊:
- stacks:缺陷的棧資訊一個數組節點類型,每個數組元素參考定義組節點definitions下的stack的定義。statck包括:
- frames:代表按調用順序排列的,按相反時間順序排列的一系列調用,這些調用構成了調用堆棧。frames是statck中一個必須的節點,frames一個數組節點類型,每個數組元素參考定義組節點definitions下的stackFrame的定義。stackFrame包括:
- location: 位置資訊,參考定義組節點definitions下的location的定義;
- module: 包含此堆棧架構代碼的子產品的名稱;
- threadId:堆棧架構的線程編号;
- parameters:函數調用的參數資訊, 是一個數組節點,每個數組元素表示一個參數;
"results": [
{
"level": "error",
"message": {
"text": "'x' is assigned a value but never used."
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "file:///C:/dev/sarif/sarif-tutorials/samples/Introduction/simple-example.js",
"index": 0
},
"region": {
"startLine": 1,
"startColumn": 5
}
}
}
],
"ruleId": "no-unused-vars",
"ruleIndex": 0
}
]
5.5. 小結
SARIF通過下面的結構,構成了一個掃描工具掃描結果的基本架構。
{
"version": "2.1.0",
"runs": [
{ // 運作結果
"tool": {
// 工具資訊
"rules": [
// 規則的資訊
]
}
},
"artifacts": [
//掃描檔案的資訊
],
"results": [ // 掃描結果
{
// 缺陷資訊
"locations": [
// 缺陷位置資訊
],
// 缺陷規則資訊
}
]
}
]
}
6. 總結
- 本篇的前半部分介紹了SARIF的需求的提出,以及成為結構化資訊标準促進組織(OASIS)的SARIF技術委員會的一個标準;
- 後半部分介紹了SARIF的基本概念,以及掃描結果的基本架構;
- 下篇将介紹對于複雜的靜态分析工具報告需求的實作。
7. 參考
- Industry leaders collaborate to define SARIF interoperability standard for detecting software defects and vulnerabilities
- OASIS Awards 2018 Open Standards Cup to KMIP for Key Management Security and SARIF for Static Analysis Tools
- OASIS Static Analysis Results Interchange Format (SARIF) Technical Committee
- SARIF Specification
- SARIF Tutorials
- Vscode Extension: Sarif Viewer
- SARIF-SDK
- Fortify FPR to SARIF
- GrammaTech SARIF integration for GitHub
- Static Analysis Results: A Format and a Protocol: SARIF & SASP
本文分享自華為雲社群《DevSecOps工具與平台互動的橋梁 -- SARIF入門》,原文作者:Uncle_Tom 。
點選關注,第一時間了解華為雲新鮮技術~