DMS定義了一套領域專用語言DSL(Domain Specific Language)用來描述安全規則。DSL語法非常靈活,理論上可以表述任意安全規則,從而幫助不同企業定義符合自己的研發規范。
DSL語法概述
DSL語法非常簡單,由分支判斷(IF-ELSE)、條件和動作三部分組成,基本形式如下。
if
條件1
then
動作1
end
還有增強形式,即else
后面還可以跟著if條件。只有if
語句是必須的,elseif
可以有0個或多個,else
可以有0個或1個。
if
條件1
then
動作1
elseif
條件2
then
動作2
[else 動作3]
end
DSL語法詳細介紹
- 條件語句
條件就是判斷語句,用來判定
true
或false
。條件語句由連接符(and
、or
)、操作符、因子(系統變量)組成。如下示例都是合法的條件語句。true // 最簡單的條件語句,結果就是true。 1 > 0 1 > 0 and 2 > 1 1 <= 0 or 1 == 1
說明 以上結果都是true。- 連接符
和其它語言一樣,
and
和or
分別是與和或連接運算,and
比or
優先級高,但它們都比操作符的優先級低。例如
1 <= 0 or 1 == 1
語句:最先執行1 <= 0
判斷,然后執行1 == 1
判斷,最后執行or
判斷。 - 操作符
操作符用于連接因子(系統變更)、常量進行相關邏輯運算,目前支持的操作符如下。
操作符 說明 示例 == 等于 1 == 1 != 不等于 1 != 2 > 大于 1 > 2 >= 大于等于 1 >= 2 < 小于 1 < 2 <= 小于等于 1 <= 2 in 包含于 ‘a’ in [‘a’, ‘b’, ‘c’] not in 不包含于 ‘a’ not in [‘a’, ‘b’, ‘c’] matchs(驗證工具) 正則匹配 'idx_aa' matchs 'idx_\\w+' not matchs 不匹配 'idx_aa' not matchs 'idx_\\w+' isBlank 為空 ‘’ isBlank isNotBlank 不為空 ‘’ isNotBlank 注意:正則表達式中(\)需要另外一個(\)轉義,例如:
idx_\w+需要寫成:idx_\\w+
。說明 操作符雖然有優先級,但不建議依賴優先級。如果條件語句較為復雜時,建議將需要先判斷的部分放在括號內。例如:1 <= 2 == true
執行順序不明確,可改為:(1 <= 2) == true
,此時一定先執行(1 <= 2)
。 - 因子
因子是系統內置變量,可用來獲取安全規則校驗的上下文信息,如獲取SQL類型、影響行數等。因子全部以
@fac.
開頭,后接因子名稱。每個模塊的不同檢測點均提供不同因子,如下為部分因子及其說明。因子名 說明 @fac.env_type 環境類型,值為環境標識,如 dev
、product
。詳情請參見實例環境說明。@fac.sql_type SQL腳本的類型,如 UPDATE
、INSERT
。@fac.detail_type 數據變更的種類: - COMMON:普通數據變更
- CHUNK_DML:無鎖數據變更
- PROCEDURE:存儲過程
- CRON_CLEAR_DATA:定時清理表
- BIG_FILE:批量數據導入
@fac.is_logic 是否為邏輯庫。 @fac.extra_info 其他變更信息(暫無用途)。 @fac.is_ignore_affect_rows 是否跳過校驗。 @fac.insert_rows 插入數據的影響行數。 @fac.update_delete_rows 更新數據的影響行數。 @fac.max_alter_table_size 修改表中,最大的表空間大小。 @fac.is_has_security_column SQL腳本中是否包含敏感列。 @fac.security_column_list SQL腳本中包含的敏感列列表。 @fac.risk_level 識別到的風險級別。 @fac.risk_reason 識別為該風險的原因。 在條件語句中,可直接引用因子,例如:
@fac.sql_type == 'DML'
,判斷SQL類型是不是DML。
- 連接符
- 動作語句
動作是滿足
if
條件之后系統執行的行為,例如:禁止提交工單、選擇工作流、允許執行、拒絕執行等,這些動作表達了安全規則的主要目的。動作全部以@act.
開頭,后接動作名稱。每個模塊的不同檢測點均提供不同動作,如下為部分動作及其說明。動作名 說明 @act.allow_submit 必須提交工單執行。 @act.allow_execute_direct 允許直接在SQL控制臺執行。 @act.forbid_execute 禁止執行。 @act.mark_risk 標記風險。用法: @act.mark_risk 'middle' '中風險:線上環境'
。@act.do_not_approve 指定審批模板ID。詳情請參見設置審批流程。 @act.choose_approve_template @act.choose_approve_template_with_reason - 內置函數
安全規則內置部分函數,在條件語句和動作語句均可以使用。函數全部以 @fun. 開頭,后面是函數名。
函數名 說明 示例 @fun.concat 拼接字符串。 返回值:字符串。
參數:任意多個字符串。@fun.concat(‘d’, ‘m’, ‘s’) // ‘dms’ @fun.concat(‘[研發規范]字段[‘,@fac.column_name, ‘]必須要填寫備注信息’) // 拼接友好的提示信息返回給用戶。
@fun.char_length 計算字符串的長度。 返回值:整數。
參數:一個字符串。@fun.char_length(‘dms’) // 3 @fun.char_length(@fac.table_name) // 計算表名長度。
@fun.is_char_lower 判斷字符串是否都是小寫。 返回值:true或false。
參數:一個字符串。@fun.is_char_lower(‘dms’) // true @fun.is_char_lower(@fac.table_name) // 返回true的話,表名都是小寫。
@fun.is_char_upper 判斷字符串是否都是大寫。 返回值:true或false。
參數:一個字符串。@fun.is_char_upper(‘dms’) // false @fun.is_char_upper(@fac.table_name) // 返回true的話,表名都是大寫。
@fun.array_size 計算集合的大小。 返回值:整數。
參數:一個集合。@fun.array_size([1, 2, 3]) // 3 @fun.array_size(@fac.table_index_array) // 計算表索引的個數。
@fun.add 多個數相加。 返回值:數值。
參數:任意多個數。@fun.add(1, 2, 3) // 6 @fun.sub 兩個數相減。 返回值:數值。
參數:2個數值。@fun.sub(6, 1) // 5 @fun.between 是否在某區間(支持數值、日期時間比較),判斷時包含邊界值。 返回值:true或false。
參數:3個參數,第一個是目標值,第二個是左區間,第三個是右區間。@fun.between(1, 1, 3) // 判斷1是否在1~3區間內,返回true。 @fun.between(2, 1, 3) // 判斷2是否在1~3區間內,返回true。
@fun.between(7, 1, 3) // 判斷7是否在1~3區間內,返回false。@fun.between(@fac.export_rows, 2001, 100000) // 判斷導出行數的范圍。
@fun.between(@fun.current_datetime(), ‘2019-10-31 00:00:00’, ‘2019-11-04 00:00:00’) // 判斷當前時間是否在10.31~11.04號之間。@fun.between(@fun.current_date(), ‘2019-10-31’, ‘2019-11-04’) // 判斷當前時間是否在10.31~11.04號之間。
@fun.current_datetime 獲取當前日期時間,格式:yyyy-MM-dd HH:mm:ss。 返回值:字符串。
參數:無。@fun.current_datetime() // 當前日期時間,例如:2019-10-31 00:00:00。 @fun.current_date 獲取當前日期,格式:yyyy-MM-dd。 返回值:字符串。
參數:無。@fun.current_date() // 當前日期,例如:2020-01-13。 @fun.current_time 獲取當前時間,格式:HH:mm:ss。 返回值:字符串。
參數:無。@fun.current_time() // 當前時間,例如:19:43:20。 @fun.is_contain_str 判斷第一個字符串是否包含第二個字符串。 返回值:true或false。
參數:2個參數,第一個是源字符串(Source),第二個是目標字符串(Target)。@fun.is_contain_str('abcd', 'ab') // 判斷"abcd"是否包含"ab",返回true。 @fun.listEqualIgnoreOrder 判斷兩個字符串List是否相同(忽略元素順序和元素的大小寫)。 返回值:true或false。
參數:2個參數,第一個是字符串List1,第二個是字符串List2。@fun.listEqualIgnoreOrder(['ab','cd'], ['Cd','ab']) // 判斷是否相同,返回true。 @fun.listEqualIgnoreOrder(@fac.perm_type, ['QUERY']) // 判斷是否僅申請了查詢權限。
@fun.listEqualIgnoreOrder(@fac.perm_type, ['CORRECT','EXPORT']) // 判斷是否同時申請了變更和導出權限。
示例
- 控制單次執行SQL個數。
if @fac.sql_count > 1000 then @act.reject_execute '單次執行SQL個數不能超過1000' else @act.allow_execute end
說明 如果SQL的數量大于1000個時,DMS即拒絕執行,并且返回相應的理由給用戶,否則就允許執行。 - 允許提交DML語句。
if @fac.sql_type in [ 'UPDATE','DELETE','INSERT','INSERT_SELECT'] then @act.allow_submit end
說明 如果提交的SQL是UPDATE
、DELETE
、INSERT
、INSERT_SELECT
類型就允許執行。