iT邦幫忙

2024 iThome 鐵人賽

DAY 27
1
DevOps

菜逼八用Github Actions系列 第 27

Day 27 - 例子 - CodeQL整合到CI

  • 分享至 

  • xImage
  •  

目錄

摘要

在上一篇我們了解了如何整合Lighthouse到CI

這篇我們會來會來了解一下CodeQL,以及如何用CodeQL做一個超簡單的檢查

什麼是CodeQL

CodeQL 是 GitHub 提供的一種靜態分析工具,用來檢查程式碼中的潛在安全漏洞,支援JavaScript、TypeScript、Python、Java、Go、C#、Kotlin等語言

它會將C#、Java程式碼直接轉換成可查詢的CodeQL資料庫,其他語言則需要自行建立CodeQL資料庫,有了CodeQL資料庫開發人員就能使用查詢語言來檢查潛在的漏洞(e.g.: SQL injection、XSS)

不過只有符合以下條件的repo能使用CodeQL

1.公開repo
2.企業版用戶的私有repo

建立CodeQL資料庫

  1. 下載CodeQL VSCode插件

  2. 下載VSIX檔,然後把選左邊sidebar的...,然後選install from visx,之後選剛剛下載的檔案進行安裝

    https://ithelp.ithome.com.tw/upload/images/20240928/20135568EuaTPvdmxI.png

  3. 左邊sidebar選QL,然後點database區的github icon去import你的repo

    https://ithelp.ithome.com.tw/upload/images/20240928/20135568UfwEdNd9Mt.png

撰寫第一個query

按shift+ctrl+P叫出VS Code的command palette,選CodeQL: Quick Query,然後選JavaScript,最後輸入CodeQL檔案要放的路徑

https://ithelp.ithome.com.tw/upload/images/20241003/20135568mowvDwJEW3.png

接著就會看到資料夾中多了一些檔案

https://ithelp.ithome.com.tw/upload/images/20241003/201355687ErCTrvaxx.png

每個 QL pack 一定要有 codeql-pack.yml,裡面包含了一些重要資訊

  • 這個 pack 是什麼: 包含query、library還是module
  • 包含哪些檔案: 這個 pack 裡有哪些query、library檔案、查詢套件等
  • 如何編譯: CodeQL 要如何編譯這些查詢(這些查詢是要針對哪種語言進行)
  • 相依性: 這個 pack 需要哪些其他的 QL pack 或外部套件
import javascript

from File f
select f, "Hello, world!"

先不管內容是甚麼,一樣打開選CodeQL: Run Query on Selected Database,或者點下方任一張圖黃圈處也可以在本地執行檢查

https://ithelp.ithome.com.tw/upload/images/20241003/20135568L26CAPj4Vm.png

https://ithelp.ithome.com.tw/upload/images/20241003/20135568lxCFs0vflN.png

之後就會看到檢查的結果囉

https://ithelp.ithome.com.tw/upload/images/20241003/201355683g3yhbVFqe.png

CodeQL query的組成

.ql檔案中只能有一個query,而一個query的結構跟SQL相當類似,由變數、select、where組成

  • 引入library

    /* 引入JavaScript、TypeScript的library */
    import javascript
    
  • 宣告變數

    定義要用於query的變數,格式為from 型別 變數名

    from Expr e
    
  • 條件

    格式為where 條件where 條件1 and 條件2

    /* e.isPure()`檢查變數e沒有side effect */
    /* e.getParent()`檢查變數e的父層是否為表達式 */
    where e.isPure() and e.getParent() instanceof ExprStmt
    

    另外需注意,如果條件是涉及值的判斷的,只能使用雙引號

    where f.getName() = "foo"
    
  • 定義檢查的項目、返回的message

    格式為select 檢查的目標, "返回的訊息"

    select e, "This expression has no effect."
    

小結

import javascript

from Expr e
where e.isPure() and
  e.getParent() instanceof ExprStmt
select e, "This expression has no effect."

整個合起來看的話整個query代表檢查所有表達式,如果發現沒有side effect且父層為表達式的表達式,就返回"This expression has no effect."

CodeQL語法

這邊只抽幾個出來大略介紹,更多內容可以看Data flow cheat sheet for JavaScript

  • .getName()
    (多個使用對象)取得變數、function、class、屬性名

    // 取得multiplier、personData
    const multiplier = (a, b) => a * b;
    const personData = {
      name: 'Jasmine',
      email: 'a123@gmail.com'
    }
    
  • .getACall()
    取得某個function被呼叫的地方

    // 找multiplier、Object.keys()被呼叫的地方
    multiplier(2, 3);
    Object.keys(personData);
    
  • .getArgument(index)
    取得傳給function的argument

    // 視傳入的index取得2或3
    multiplier(2, 3);
    
  • .getParameter(index)
    取得傳給function的parameter

    // 視傳入的index取得a或b
    const multiplier = (a, b) => a * b;
    
  • .getRhs()
    (多個使用對象)取得賦值表達式右側的內容

    // 會取得100
    tempNum = 100;
    // 會取得365
    constantNumber = 365;
    
  • .getAPropertyRead(propName)
    取得讀取物件屬性值的地方

    console.log(personData.userName);
    
  • .getAPropertyWrite(propName)
    取得某物件屬性被賦予值的地方

    personData.userName = 'Tempura';
    
  • .getAPropertySource(prop)
    取得賦予給物件屬性的值

    // 尋找賦值為"Tempura"的地方
    personData.userName = 'Tempura';
    
  • .hasFlowPath(source, sink)、
    檢查兩個變數或表達式之間是否存在data flow

    // 以下兩個變數存在data flow
    tempNum = constantNumber;
    
  • .hasFlow(source, sink)
    檢查兩個表達式之間是否存在data flow

    // 以下兩個變數存在data flow
    let days = constantNumber;
    
  • .getAMethodCall(methodName)
    和.getACall()類似,但只取得某個物件、class中的方法被呼叫的地方

    Object.keys(bar);
    [].push(1);
    

撰寫workflow

name: Try CodeQL

on:
  push:
    branches:
      - master

# 如果Workflow permissions設為"Read repository contents and packages permissions"代表是restricted模式,
# restricted模式下GITHUB_TOKEN就只會有content和package的read權限,此時就需要在workflow內設定permission
# 關於restriced、permissive模式有的預設權限看https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
permissions:
  actions: read
  security-events: write

jobs:
  give-a-try:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      # Initializes CodeQL tools and creates a codebase for analysis.
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: JavaScript
          # 如果是需要編譯的語言則要在定義build-mode,或自行寫build指令,JavaScript、TypeScript這兩者皆不需要
          # build-mode: autobuild

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          category: "/language:JavaScript"
          output: check-results
          upload: failure-only

完成後每次push就會到master就會做檢查

https://ithelp.ithome.com.tw/upload/images/20241005/20135568vRaPRZnP6g.png

log內有個連結,點下去會導到tools/CodeQL,點黃圈處可以看最新的CodeQL report

https://ithelp.ithome.com.tw/upload/images/20241005/20135568FszZLZl6g8.png


上一篇
Day 26 - 例子 - Lighthouse整合到CI
下一篇
Day 28 - 比較Github Actions 與 Jenkins
系列文
菜逼八用Github Actions30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言