新手区 实践:火线静态代码扫描以及定位错误代码作者

刘彬伟 · September 04, 2017 · Last by securitytest replied at September 26, 2017 · 1244 hits
本帖已被设为精华帖!

基本思路:

每一行代码都有作者, 错误的代码更应该有作者。
本文的思路是, 通过火线静态代码扫描程序扫描后的json报告, 直接定位到人,也就是错误代码的引入者。
责任到人,可以更好地做到错误代码发现及时, 修复更及时。

准备条件:

  1. 火线静态代码扫描程序
    1). 下载火线jar包 http://magic.360.cn/index.html
    2). 编写配置文件 RedLineConfigurationNoLog.xml http://magic.360.cn/user.html#args

  2. 代码扫描服务器 - Linux CentOS 6 or 7
    1). 安装JDK
    2). 准备预扫描项目的git目录,例如:/data/git/test
    3). 发布WEB服务的文件夹, 用于发布火线报告HTML版, 例如: /data/webtest/fireline
    3). jq 用于解析火线json报告的内容,
    CentOS 7:yum install -y jq,
    CentOS 6:需要自行下载安装,https://stedolan.github.io/jq/

脚本执行步骤:

一、火线静态代码扫描

  1. git pull 更新扫描服务器上的代码
  2. 执行火线静态代码扫描命令
  3. 发布火线扫描报告html

二、定位错误代码作者

  1. 检查火线扫描报告json文件内block和error条目的数量
  2. 根据错误代码的文件名和出错行数查找错误代码作者

脚本内容(/data/fireline/fireline.sh):

#! /bin/sh
# Author : binwei.liu
# Usage: 2017-09-02 火线静态代码扫描以及定位错误代码作者

#########################################
# 一、火线静态代码扫描
#########################################
# 1. git pull 更新扫描服务器上的代码
# 2. 执行火线静态代码扫描命令
# 3. 发布火线扫描报告html
#########################################
# 二、定位错误代码作者
#########################################
# 4. 检查火线扫描报告json文件内block和error条目的数量
# 5. 根据错误代码的文件名和出错行数查找错误代码作者
#########################################

PS4='+[$LINENO]'
RUN_TIME=$( date +'%Y%m%dT%H%M%S' )

# 设置扫描项目名称
# FIRELINE_PROJ_NAME=${1}
FIRELINE_PROJ_NAME='test'
# 设置已经准备好的项目git目录
# FIRELINE_SCAN_SRC_DIR=${2}
FIRELINE_SCAN_SRC_DIR='/data/git/test'

# 火线报告临时存放文件夹
FIRELINE_REPORT_SAVE_DIR="/tmp/report_${FIRELINE_PROJ_NAME}_${RUN_TIME}"
# 火线报告文件名
FIRELINE_REPORT_FILE_NAME="index_${FIRELINE_PROJ_NAME}"
# 火线报告提交人名称
FIRELINE_USER='binwei.liu'
# 火线程序jar包
FIRELINE_JAR='/data/fireline/fireline.jar'
# 火线程序配置文件路径
FIRELINE_CONFIG='/data/fireline/RedLineConfigurationNoLog.xml'
# 扫描服务器上,web服务发布的文件夹
PUBLIC_REPORT_DIR='/data/webtest/fireline'
# 火线报告内的json文件
FIRELINE_REPORT_JSON_FILE="/data/webtest/fireline/${FIRELINE_REPORT_FILE_NAME}.json"
# web报告发布后的查看地址
PUBLIC_REPORT_URL="http://www.17test.net/fireline/${FIRELINE_REPORT_FILE_NAME}.html"
# json报告里包含block条目的数量
JSON_BLOCK_ITEM_COUNT=0
# json报告里包含error条目的数量
JSON_ERROR_ITEM_COUNT=0

# 日志屏幕显示或者记录到指定文件
function log () {
# echo -e `date +'%Y-%m-%d %H:%M:%S'` "${*}" | tee -a ${LOG_FILE}
# echo -e "${*}" | tee -a ${LOG_FILE}
echo -e "${*}"
}

function init () {
log "##################################################"
log "报告链接: ${PUBLIC_REPORT_URL}"
log "规则文档: http://magic.360.cn/document.html"
log "##################################################"

# 建立报告临时存放文件夹
log "info: create new tmp report folder ${FIRELINE_REPORT_SAVE_DIR}"
mkdir -p ${FIRELINE_REPORT_SAVE_DIR}
}

function finalize () {
log "${2}"
exit ${1}
}

function update_local_code () {
log "info: update the local code to the latest."

cd ${FIRELINE_SCAN_SRC_DIR}
git reset --hard origin/master && \
git gc && \
git pull && \
git submodule init && \
git submodule update && \
git submodule foreach git checkout master && \
git submodule foreach git pull

if [[ $? -ne 0 ]]; then
finalize 1 "error: update the local code failed."
fi
}

function fireline_scan () {
log "info: fireline starts to scan the project of <${FIRELINE_PROJ_NAME}>"
java -jar ${FIRELINE_JAR} \
-Df ile.encoding=UTF-8 \
scanSrcDir=${FIRELINE_SCAN_SRC_DIR} \
reportSaveDir=${FIRELINE_REPORT_SAVE_DIR} \
reportFileName=${FIRELINE_REPORT_FILE_NAME} \
proj_name=${FIRELINE_PROJ_NAME} \
user=${FIRELINE_USER} \
config=${FIRELINE_CONFIG} > /dev/null 2&>1

if [[ $? -ne 0 ]]; then
finalize 1 "error: fireline scans project <${FIRELINE_PROJ_NAME}> failed."
else
log "info: fireline scans completely."
fi
}

function public_report_html () {
log "info: public the fireline report."

cp -rf ${FIRELINE_REPORT_SAVE_DIR}/* ${PUBLIC_REPORT_DIR}/

if [[ $? -ne 0 ]]; then
log "error: public the fireline report failed."
fi
}

function find_author_of_error_code () {
local _beginline=${1}
local _endline=${2}
local _filepath=${3}

log "author:"
cd ${FIRELINE_SCAN_SRC_DIR}
git blame -L ${_beginline},${_endline} ${_filepath}

if [[ $? -ne 0 ]]; then
finalize 1 "error: git blame -L ${_beginline},${_endline} ${_filepath} failed."
fi
}

function get_item_count_by_level () {
local _level=${1}

jq ".${_level} | length" ${FIRELINE_REPORT_JSON_FILE}

if [[ $? -ne 0 ]]; then
finalize 1 "error: get the count of <${_level}> level failed."
fi
}

function get_element_value_from_item () {
local _level=${1}
local _no=${2}
local _key=${3}

jq -r ".${_level}[] | select(.no == \"${_no}\") | .${_key}" ${FIRELINE_REPORT_JSON_FILE}

if [[ $? -ne 0 ]]; then
finalize 1 "error: get the key <level:${_level}, no:${2}, key:${_key}> failed."
fi
}

function get_json_item_count () {
JSON_BLOCK_ITEM_COUNT=$( get_item_count_by_level 'block' )
JSON_ERROR_ITEM_COUNT=$( get_item_count_by_level 'error' )
}

function print_items_details () {
local _level=${1}
local _count=${2}

log "info: show the items of <${_level}>"

for ((i=1; i<=${_count}; i++)); do
_no=${i}
_classname=$( get_element_value_from_item ${_level} ${_no} 'classname' )
_filepath=$( get_element_value_from_item ${_level} ${_no} 'filepath' )
_rulename=$( get_element_value_from_item ${_level} ${_no} 'rulename' )
_rule_description=$( get_element_value_from_item ${_level} ${_no} 'ruleDescription' )
_docurl=$( get_element_value_from_item ${_level} ${_no} 'docurl' )
_beginline=$( get_element_value_from_item ${_level} ${_no} 'beginline' )
_endline=$( get_element_value_from_item ${_level} ${_no} 'endline' )

log "---- ${_no} ----"
log "classname: ${_classname}"
log "filepath: ${_filepath}"
log "rulename: ${_rulename}"
log "ruleDescription: ${_rule_description}"
log "docurl: ${_docurl}"
log "beginline: ${_beginline}"
log "endline: ${_endline}"

find_author_of_error_code ${_beginline} ${_endline} ${_filepath}
done
}

function main () {
# 初始化
init

# 1. git pull 更新扫描服务器上的代码
update_local_code

# 2. 执行火线静态代码扫描命令
fireline_scan

# 3. 发布火线扫描报告html
public_report_html

# 4. 检查火线扫描报告json文件内block和error条目的数量
get_json_item_count

# 5. 根据错误代码的文件名和出错行数查找错误代码作者
if [[ ${JSON_BLOCK_ITEM_COUNT}>0 ]]; then
log "fail: there are some code issues about <block> level."
print_items_details 'block'${JSON_BLOCK_ITEM_COUNT}
else
log "info: not found the code issues about <block> level."
fi

if [[ ${JSON_ERROR_ITEM_COUNT}>0 ]]; then
log "fail: there are some code issues about <error> level."
print_items_details 'error' ${JSON_ERROR_ITEM_COUNT}
else
log "info: not found the code issues about <error> level."
fi
}

main

脚本执行结果:

[root@VM-TEST-96 fireline]# bash /data/fireline/fireline.sh 
##################################################
报告链接: http://www.17test.net/fireline/index_test.html
规则文档: http://magic.360.cn/document.html
##################################################
info: create new tmp report folder /tmp/report_test_20170904T201126
info: update the local code to the latest.
HEAD is now at e096a44 edit errot01 02 03
Counting objects: 15, done.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (15/15), done.
Total 15 (delta 2), reused 15 (delta 2)
Already up-to-date.
info: fireline starts to scan the project of <test>
info: fireline scans completely.
info: public the fireline report.
info: not found the code issues about <block> level.
fail: there are some code issues about <error> level.
info: show the items of <error>
---- 1 ----
classname: TestFireline
filepath: /data/git/test/src/test/TestFireline.java
rulename: 错位的空判断
ruleDescription: 这里的空检查是放错位置的。如果变量为空你将得到一个空指针异常。可能因为检查是无用的或者是不正确的。如:if (!string.equals("") && string!=null){}
docurl: http://magic.360.cn/document.html#CodeStyle-11
beginline: 53
endline: 53
author:
013d7a2d (binwei.liu 2017-09-04 15:39:29 +0800 53) if (a.equals(baz) && a != null) {}
---- 2 ----
classname: TestFireline
filepath: /data/git/test/src/test/TestFireline.java
rulename: 破坏空判断
ruleDescription: 如果自身抛出空指针异常空检查就会遭到破坏,比如你使用 代替 &&,反之亦然,如(应是&&):if (string!=null !string.equals("")){}
docurl: http://magic.360.cn/document.html#CodeStyle-13
beginline: 60
endline: 62
author:
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 60) if (string!=null || !string.equals("")) {
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 61) return string;
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 62) }
---- 3 ----
classname: TestFireline
filepath: /data/git/test/src/test/TestFireline.java
rulename: 破坏空判断
ruleDescription: 如果自身抛出空指针异常空检查就会遭到破坏,比如你使用 代替 &&,反之亦然,如(应是&&):if (string!=null !string.equals("")){}
docurl: http://magic.360.cn/document.html#CodeStyle-13
beginline: 65
endline: 67
author:
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 65) if (string==null && string.equals("")) {
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 66) return string;
e096a440 (binwei.liu 2017-09-04 16:16:25 +0800 67) }
[root@VM-TEST-96 fireline]#

火线json报告内容(/data/webtest/fireline/index_test.json):

{
"block": [],
"error": [
{
"no": "1",
"classname": "TestFireline",
"filepath": "/data/git/test/src/test/TestFireline.java",
"rulename": "错位的空判断",
"ruleDescription": "这里的空检查是放错位置的。如果变量为空你将得到一个空指针异常。可能因为检查是无用的或者是不正确的。如:if (!string.equals(\"\") && string!=null){}。",
"docurl": "http://magic.360.cn/document.html#CodeStyle-11",
"beginline": "53",
"endline": "53"
},
{
"no": "2",
"classname": "TestFireline",
"filepath": "/data/git/test/src/test/TestFireline.java",
"rulename": "破坏空判断",
"ruleDescription": "如果自身抛出空指针异常空检查就会遭到破坏,比如你使用 代替 &&,反之亦然,如(应是&&):if (string!=null !string.equals(\"\")){}。",
"docurl": "http://magic.360.cn/document.html#CodeStyle-13",
"beginline": "60",
"endline": "62"
},
{
"no": "3",
"classname": "TestFireline",
"filepath": "/data/git/test/src/test/TestFireline.java",
"rulename": "破坏空判断",
"ruleDescription": "如果自身抛出空指针异常空检查就会遭到破坏,比如你使用 代替 &&,反之亦然,如(应是&&):if (string!=null !string.equals(\"\")){}。",
"docurl": "http://magic.360.cn/document.html#CodeStyle-13",
"beginline": "65",
"endline": "67"
}
]
}

鸣谢: @oggboy (丁老九), 完善了火线json报告,使代码扫描和定位责任人两部分结合起来, 实现完整的自动化。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 17 条回复 时间 点赞

请使用火线 2017.09.04 之后的版本

思寒_seveniruby 将本帖设为了精华贴 04 Sep 21:48

"火线静态代码扫描以及定位错误代码作者",标题是不是多了“作者”????

执行的效果是怎样的?截个图看看

火线已经发布1.3.2版(magic.360.cn),扫描后会生成文章中的JSON报告。

simple 回复

文章内的执行结果部分就是, 我直接粘贴的执行结果文本。

willys 回复

就是定位到代码的作者, 通过 git blame 来显示错误代码的编写人。

顶下,接下来要搞扫描规则了。

刘彬伟 回复

soga

赞,赞,赞。学习了。
我们公司也在用火线扫描。

Arya 回复

👍 可以帮忙指点一下,文章里使用不完善的地方,帮我们改进。 🙏

请问怎么自定义检查规则?

是360的代码安全检查产品吗

蒋刚毅 回复

不止是安全检测,还有缺陷类的检测,总共100多条规则

不舍昼夜 回复

目前自定义规则都是我们内部定制完了,在公司的编译平台上跑一段时间没问题才公布出来的。如果想自己定义规则可以联系这边的同学

适用了一下,和jenkins集成了,方便,好用,效果也不错~赞

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 13 Dec 20:49
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up