作成: 2020年12月08日
更新: 2021年03月29日
この記事はセキュリティ Advent Calendar 2020 - Qiitaの9日目です.
静的解析ツールCodeQLのCLI版を用いてセキュリティ脆弱性の発見をテストしてみました.
CodeQLは静的解析ツール一種でソースコードをデータベースのように扱い,脆弱性を引き起こすパターンや冗長なコードのパターンをクエリとしてデータベース化されたソースコードに対して実行することで脆弱性を発見できます.
シンプルな例として以下のクエリはPythonコードの中でpassしか含まれていない冗長なif文を検出します.
import python
from If ifstmt, Stmt pass
where pass = ifstmt.getStmt(0) and
pass instanceof Pass
select ifstmt, "This 'if' statement is redundant."
passしか含まれていない冗⻑なif⽂の例
if is_checked == True:
print("Check")
else:
pass
同様の⽅法で脆弱性を引き起こすコードのパターンを検出できる.
この記事ではLGTMというサービスが包括的なセキュリティチェックに使⽤しているクエリをCLIを用いて実際に実行してみる.
またセキュリティチェックの対象としてDjango製のeasybuggy4djangoを用いる.easybuggy4djangoはSQLインジェクションやデッドロックなど有名な脆弱性が山ほど含まれてます.easybuggy4djangoはPython3.7以降では動かないみたいなので注意.
Windows 10のWSL上で実行しました.
CodeQL CLIのセットアップ
wget https://github.com/github/codeql-clibinaries/releases/latest/download/codeql.zip
unzip codeql
mkdir ~/codeql-home
mv codeql ~/codeql-home/
解析に必要なCodeQLクエリのクローン
git clone https://github.com/github/codeql.git
mv codeql codeql-repo
mv codeql-repo ~/codeql-home/
easybuggy4djangoのクローン
git clone https://github.com/k-tamura/easybuggy4django.git
cd easybuggy4django
easybuggy4djangoのデータベース構築
~/codeql-home/codeql/codeql databse create codeql-db --language=python
解析
python-security-and-qualityを指定することでセキュリティに関するクエリセットを実行しています.
mkdir codeql-result
~/codeql-home/codeql/codeql databse analyze "codeql-db" python-security-and-quality
--format=sarif-latest --output=codeql-resutlt/security-and-quality.
sarif
codeql-resutlt/security-and-quality.sarif に解析結果が出⼒される.
sarifファイルはVSCodeの拡張機能Sarif Viewer - Visual Studio Marketplace で見ることができます.
SQLインジェクションなどの脆弱性がしっかり検出できています.
SQLインジェクションを起こしているソースコードでは以下のようになっています.
def sql_injection(request):
d = {
'title': _('title.sqlijc.page'),
'note': _('msg.note.sqlijc'),
}
if request.method == 'POST':
name = request.POST.get("name")
password = request.POST.get("password")
d['users'] = User.objects.raw("SELECT * FROM easybuggy_user WHERE ispublic = 'true' AND name='" + name + "' AND password='" + password + "' ORDER BY id")
return render(request, 'sqlijc.html', d)
変数を含む生SQLを検知しているのだと思います.
一方で検出できていない脆弱性もありました.
以下はDjangoのテンプレート記法で書かれていてXSSを起こします.
{% extends "base.html" %}
{% load i18n %}
{% block body %}
{% include "header.html" %}
<form action="" method="post" enctype="application/x-www-form-urlencoded">
{% csrf_token %}
<p>{% trans 'description.reverse.string' %}</p><br/>
<label>{% trans 'label.string' %}</label><span>: </span>
<input type="text" name="string" size="100" maxlength="100"/><br/>
<br/> <input type="submit" value="{% trans 'label.submit' %}"/><br/><br/>
{% autoescape off %}
<p>{{ msg }}</p><br/>
{% endautoescape %}
<div class="alert alert-info" role="alert">
<span class="glyphicon glyphicon-info-sign"></span>
{% trans 'msg.note.xss' %}
</div>
</form>
{% endblock %}
Djangoのもつエスケープ機能を{% autoescape off %}
でキャンセルしているためXSSが起こってしまう.これはDjangoというフレームワーク由来で起きる脆弱性でこのようなものは検知できない(HTMLやJavaScriptとしてCodeQLを実行しても検知できない)
CodeQL CLIを用いてセキュリティ解析を行ってみました.
CodeQLはまだ発展途上ではありますがGithubが公式にサポートしていることもあり今後のコミュニティの発展がとても楽しみです.