CLOVER🍀

That was when it all began.

Semgrepでルヌルセットやルヌルを適甚する

これは、なにをしたくお曞いたもの

Semgrepを扱ったこちらの゚ントリヌの続きです。

SASTツール、Semgrep Community Editionを試す - CLOVER🍀

Semgrepを実行する際に指定するルヌルセットやルヌルの指定方法を芋おいきたす。

ルヌルセットやルヌルの指定方法

Semgrepに適甚するルヌルセットやルヌルを指定するには、--configオプションを䜿いたす。

こんな感じですね。

$ semgrep scan --config p/default

Get started | Semgrep

Customize scans | Semgrep

これが基本です。

ルヌルセットずいうのは文字通りルヌルをたずめたものですが、ルヌルセット自䜓はSemgrepチヌムが管理しおいお、Semgrep Registryで
公開されたす。

Rules can be organized in rulesets. Rulesets are rules related through a programming language, OWASP category, or framework. The rulesets are curated by the team at Semgrep and updated as new rules are added to the Semgrep Registry.

Run rules | Semgrep

ルヌルセットやルヌルはSemgrep Registryで探したす。

Semgrep Registry / Explore

トップペヌゞに䞊んでいるのはルヌルセットですね。

Pythonのルヌルセット。

p/python

このように、蚀語やフレヌムワヌクなどでたずめられたルヌルセットがありたす。

どのようなルヌルセットがあるのかを確認したい堎合は、以䞋から芋るずよいでしょう。「show all」で展開されたす。

Semgrep Registry / r

含たれおいるルヌルも確認できたす。Semgrep Community Editionを䜿う堎合は、Visibilityを「Community (Public)」にしお絞り蟌むず
よいでしょう。

個々のルヌルは展開するず芋れたす。

semgrepコマンドでの指定方法は、「Run locally」リンクをクリックするず衚瀺されたす。

こういう感じですね。

$ semgrep --config="r/python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec"

぀たり、ルヌルセットはp/[ルヌルセット名]、ルヌルはr/[ルヌル名]で指定するこずになりそうです。

Semgrep Registryの怜玢機胜でルヌルを探しおもいいでしょう。

ルヌルセットやルヌルなどを耇数指定したい堎合は、--configオプションを繰り返し指定したす。
※指定しおいるルヌルはルヌルセットに含たれおいるので実質的な効果はありたせん

$ semgrep scan --config p/default --config p/python --config r/python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec

Run rules / Run multiple rules simultaneously

環境倉数でSEMGREP_RULES指定するこずもできたす。

$ SEMGREP_RULES=p/auto semgrep scan

Continuous integration (CI) environment variables / Environment variables for configuring scan behavior/ SEMGREP_RULES

耇数指定する堎合は、スペヌスで区切るようです。

$ SEMGREP_RULES='p/auto p/default' semgrep scan

ちなみに、陀倖するルヌルは--exclude-ruleオプションで指定したす。

CLI reference | Semgrep

蚭定ファむル

ずころで、ルヌルがたくさんあるず自分でルヌルセットずいうかプロゞェクトごずに適甚したいルヌルをたずめたくなる気がするのですが、
どうもそういう蚭定ができる気がしたせん。

出おくるのは、独自のルヌルの䜜り方です。

Run rules / Create and use local rules

Write rules

こういうのは、商甚版であるSemgrep Codeを䜿っおUIで蚭定しおもらう想定でいるのかなず思いたす。

Manage rules and policies | Semgrep

さお、どうしたしょう。

semgrep-rulesをcloneしお適甚する

やり方のひず぀ずしおは、semgrep-rulesリポゞトリヌをcloneしお適甚するこずでしょうか。

$ git clone https://github.com/semgrep/semgrep-rules

こんな感じで、--configオプションで指定すればOKです。

$ semgrep scan --config /path/to/semgrep-rules/generic --config /path/to/semgrep-rules/python

党郚カスタムルヌルずしお扱われおいるこずになるんでしょうね。

なんずなく、甚意されおいるルヌルセットで運甚した方が楜な気がしたす 。

環境

今回確認した環境はこちら。

$ semgrep --version
1.142.0

オマケ適甚されおいるルヌルを確認する

こちらの゚ントリヌで--debugオプションを぀ければ䞀時的にJSONファむルが出力されるので、それを芋るずよさそう、みたいなこずを
曞きたした。

$ semgrep --config auto --debug

SASTツール、Semgrep Community Editionを試す - CLOVER🍀

こういうのですね。

[00.05][INFO]: Parsing rules in /tmp/tmp_ja8xkz7.json
[00.23][DEBUG](default): read targets from file: /tmp/tmpwh0sugb5
[00.23][DEBUG](default): Core_scan.scan_exn { Core_scan_config.rule_source = Rule_file (/tmp/tmp_ja8xkz7.json);

詊しおみたす。こういうコマンドを実行䞭に

$ semgrep scan --config p/python

生成されたJSONファむルを保存。

$ cat /tmp/*.json | tee python.json

ルヌルのidを出力しおみたす。

$ cat python.json | jq .rules[].id

こうなりたした。

"python.boto3.security.hardcoded-token.hardcoded-token"
"python.cryptography.security.insecure-cipher-algorithms.insecure-cipher-algorithm-idea"
"python.cryptography.security.insecure-cipher-mode-ecb.insecure-cipher-mode-ecb"
"python.cryptography.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1"
"python.cryptography.security.insufficient-dsa-key-size.insufficient-dsa-key-size"
"python.cryptography.security.insufficient-ec-key-size.insufficient-ec-key-size"
"python.cryptography.security.insufficient-rsa-key-size.insufficient-rsa-key-size"
"python.distributed.security.require-encryption"
"python.django.security.audit.avoid-insecure-deserialization.avoid-insecure-deserialization"
"python.django.security.injection.open-redirect.open-redirect"
"python.django.security.injection.reflected-data-httpresponse.reflected-data-httpresponse"
"python.django.security.injection.reflected-data-httpresponsebadrequest.reflected-data-httpresponsebadrequest"
"python.django.security.injection.request-data-fileresponse.request-data-fileresponse"
"python.django.security.injection.request-data-write.request-data-write"
"python.django.security.injection.code.user-eval-format-string.user-eval-format-string"
"python.django.security.injection.code.user-eval.user-eval"
"python.django.security.injection.code.user-exec-format-string.user-exec-format-string"
"python.django.security.injection.code.user-exec.user-exec"
"python.django.security.injection.command.command-injection-os-system.command-injection-os-system"
"python.django.security.injection.email.xss-html-email-body.xss-html-email-body"
"python.django.security.injection.email.xss-send-mail-html-message.xss-send-mail-html-message"
"python.django.security.injection.path-traversal.path-traversal-open.path-traversal-open"
"python.django.security.injection.sql.sql-injection-extra.sql-injection-using-extra-where"
"python.django.security.injection.sql.sql-injection-rawsql.sql-injection-using-rawsql"
"python.django.security.injection.sql.sql-injection-using-db-cursor-execute.sql-injection-db-cursor-execute"
"python.django.security.injection.sql.sql-injection-using-raw.sql-injection-using-raw"
"python.django.security.injection.ssrf.ssrf-injection-requests.ssrf-injection-requests"
"python.django.security.injection.ssrf.ssrf-injection-urllib.ssrf-injection-urllib"
"python.django.security.passwords.password-empty-string.password-empty-string"
"python.django.security.passwords.use-none-for-password-default.use-none-for-password-default"
"python.flask.security.audit.app-run-param-config.avoid_app_run_with_bad_host"
"python.flask.security.audit.app-run-security-config.avoid_using_app_run_directly"
"python.flask.security.audit.debug-enabled.debug-enabled"
"python.flask.security.audit.directly-returned-format-string.directly-returned-format-string"
"python.flask.security.injection.os-system-injection.os-system-injection"
"python.flask.security.injection.path-traversal-open.path-traversal-open"
"python.flask.security.injection.ssrf-requests.ssrf-requests"
"python.flask.security.injection.user-eval.eval-injection"
"python.flask.security.injection.user-exec.exec-injection"
"python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret"
"python.jwt.security.jwt-none-alg.jwt-python-none-alg"
"python.jwt.security.unverified-jwt-decode.unverified-jwt-decode"
"python.lang.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1"
"python.lang.security.insecure-hash-function.insecure-hash-function"
"python.lang.security.unverified-ssl-context.unverified-ssl-context"
"python.lang.security.audit.ssl-wrap-socket-is-deprecated.ssl-wrap-socket-is-deprecated"
"python.lang.security.audit.subprocess-shell-true.subprocess-shell-true"
"python.lang.security.audit.weak-ssl-version.weak-ssl-version"
"python.lang.security.audit.insecure-transport.requests.request-session-http-in-with-context.request-session-http-in-with-context"
"python.lang.security.audit.insecure-transport.requests.request-session-with-http.request-session-with-http"
"python.lang.security.audit.insecure-transport.requests.request-with-http.request-with-http"
"python.lang.security.audit.logging.logger-credential-leak.python-logger-credential-disclosure"
"python.lang.security.audit.network.bind.avoid-bind-to-all-interfaces"
"python.lang.security.audit.network.disabled-cert-validation.disabled-cert-validation"
"python.lang.security.audit.network.http-not-https-connection.http-not-https-connection"
"python.lang.security.deserialization.avoid-pyyaml-load.avoid-pyyaml-load"
"python.lang.security.deserialization.avoid-unsafe-ruamel.avoid-unsafe-ruamel"
"python.lang.security.deserialization.pickle.avoid-shelve"
"python.pycryptodome.security.insecure-cipher-algorithm.insecure-cipher-algorithm-xor"
"python.pycryptodome.security.insecure-hash-algorithm.insecure-hash-algorithm-sha1"
"python.pycryptodome.security.insufficient-dsa-key-size.insufficient-dsa-key-size"
"python.pycryptodome.security.insufficient-rsa-key-size.insufficient-rsa-key-size"
"python.sqlalchemy.security.sqlalchemy-sql-injection.sqlalchemy-sql-injection"
"python.pymongo.security.mongodb.mongo-client-bad-auth"
"python.lang.security.audit.insecure-file-permissions.insecure-file-permissions"
"python.django.security.injection.raw-html-format.raw-html-format"
"python.flask.security.injection.raw-html-concat.raw-html-format"
"python.flask.security.injection.tainted-url-host.tainted-url-host"
"python.flask.security.injection.tainted-sql-string.tainted-sql-string"
"python.lang.security.audit.md5-used-as-password.md5-used-as-password"
"python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text"
"python.aws-lambda.security.dangerous-asyncio-create-exec.dangerous-asyncio-create-exec"
"python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec"
"python.aws-lambda.security.dangerous-asyncio-shell.dangerous-asyncio-shell"
"python.aws-lambda.security.dangerous-spawn-process.dangerous-spawn-process"
"python.aws-lambda.security.dangerous-subprocess-use.dangerous-subprocess-use"
"python.aws-lambda.security.dangerous-system-call.dangerous-system-call"
"python.aws-lambda.security.mysql-sqli.mysql-sqli"
"python.aws-lambda.security.psycopg-sqli.psycopg-sqli"
"python.aws-lambda.security.pymssql-sqli.pymssql-sqli"
"python.aws-lambda.security.pymysql-sqli.pymysql-sqli"
"python.aws-lambda.security.sqlalchemy-sqli.sqlalchemy-sqli"
"python.aws-lambda.security.tainted-code-exec.tainted-code-exec"
"python.aws-lambda.security.tainted-html-response.tainted-html-response"
"python.aws-lambda.security.tainted-sql-string.tainted-sql-string"
"python.django.security.nan-injection.nan-injection"
"python.flask.security.injection.nan-injection.nan-injection"
"python.aws-lambda.security.tainted-html-string.tainted-html-string"
"python.jinja2.security.audit.autoescape-disabled-false.incorrect-autoescape-disabled"
"python.jinja2.security.audit.missing-autoescape-disabled.missing-autoescape-disabled"
"python.aws-lambda.security.dynamodb-filter-injection.dynamodb-filter-injection"
"python.pyramid.audit.authtkt-cookie-httponly-unsafe-default.pyramid-authtkt-cookie-httponly-unsafe-default"
"python.pyramid.audit.authtkt-cookie-httponly-unsafe-value.pyramid-authtkt-cookie-httponly-unsafe-value"
"python.pyramid.audit.authtkt-cookie-samesite.pyramid-authtkt-cookie-samesite"
"python.pyramid.audit.authtkt-cookie-secure-unsafe-default.pyramid-authtkt-cookie-secure-unsafe-default"
"python.pyramid.audit.authtkt-cookie-secure-unsafe-value.pyramid-authtkt-cookie-secure-unsafe-value"
"python.pyramid.audit.csrf-origin-check-disabled-globally.pyramid-csrf-origin-check-disabled-globally"
"python.pyramid.audit.csrf-origin-check-disabled.pyramid-csrf-origin-check-disabled"
"python.pyramid.audit.set-cookie-httponly-unsafe-default.pyramid-set-cookie-httponly-unsafe-default"
"python.pyramid.audit.set-cookie-httponly-unsafe-value.pyramid-set-cookie-httponly-unsafe-value"
"python.pyramid.audit.set-cookie-samesite-unsafe-default.pyramid-set-cookie-samesite-unsafe-default"
"python.pyramid.audit.set-cookie-samesite-unsafe-value.pyramid-set-cookie-samesite-unsafe-value"
"python.pyramid.audit.set-cookie-secure-unsafe-default.pyramid-set-cookie-secure-unsafe-default"
"python.pyramid.audit.set-cookie-secure-unsafe-value.pyramid-set-cookie-secure-unsafe-value"
"python.pyramid.security.csrf-check-disabled-globally.pyramid-csrf-check-disabled-globally"
"python.pyramid.security.direct-use-of-response.pyramid-direct-use-of-response"
"python.pyramid.security.sqlalchemy-sql-injection.pyramid-sqlalchemy-sql-injection"
"python.aws-lambda.security.tainted-pickle-deserialization.tainted-pickle-deserialization"
"python.lang.security.audit.dangerous-asyncio-exec-tainted-env-args.dangerous-asyncio-exec-tainted-env-args"
"python.lang.security.audit.dangerous-asyncio-shell-tainted-env-args.dangerous-asyncio-shell-tainted-env-args"
"python.lang.security.audit.dangerous-code-run-tainted-env-args.dangerous-interactive-code-run-tainted-env-args"
"python.lang.security.audit.dangerous-os-exec-tainted-env-args.dangerous-os-exec-tainted-env-args"
"python.lang.security.audit.dangerous-spawn-process-tainted-env-args.dangerous-spawn-process-tainted-env-args"
"python.lang.security.audit.dangerous-subinterpreters-run-string-tainted-env-args.dangerous-subinterpreters-run-string-tainted-env-args"
"python.lang.security.audit.dangerous-subprocess-use-tainted-env-args.dangerous-subprocess-use-tainted-env-args"
"python.lang.security.audit.dangerous-system-call-tainted-env-args.dangerous-system-call-tainted-env-args"
"python.lang.security.audit.dangerous-testcapi-run-in-subinterp-tainted-env-args.dangerous-testcapi-run-in-subinterp-tainted-env-args"
"python.lang.security.dangerous-code-run.dangerous-interactive-code-run"
"python.lang.security.dangerous-os-exec.dangerous-os-exec"
"python.lang.security.dangerous-spawn-process.dangerous-spawn-process"
"python.lang.security.dangerous-subinterpreters-run-string.dangerous-subinterpreters-run-string"
"python.lang.security.dangerous-subprocess-use.dangerous-subprocess-use"
"python.lang.security.dangerous-system-call.dangerous-system-call"
"python.lang.security.dangerous-testcapi-run-in-subinterp.dangerous-testcapi-run-in-subinterp"
"python.django.security.injection.command.subprocess-injection.subprocess-injection"
"python.django.security.injection.csv-writer-injection.csv-writer-injection"
"python.flask.security.injection.csv-writer-injection.csv-writer-injection"
"python.flask.security.injection.subprocess-injection.subprocess-injection"
"python.cryptography.security.mode-without-authentication.crypto-mode-without-authentication"
"python.pycryptodome.security.mode-without-authentication.crypto-mode-without-authentication"
"python.cryptography.security.insecure-cipher-algorithms-arc4.insecure-cipher-algorithm-arc4"
"python.cryptography.security.insecure-cipher-algorithms-blowfish.insecure-cipher-algorithm-blowfish"
"python.cryptography.security.insecure-hash-algorithms-md5.insecure-hash-algorithm-md5"
"python.lang.security.insecure-hash-algorithms-md5.insecure-hash-algorithm-md5"
"python.pycryptodome.security.insecure-cipher-algorithm-blowfish.insecure-cipher-algorithm-blowfish"
"python.pycryptodome.security.insecure-cipher-algorithm-des.insecure-cipher-algorithm-des"
"python.pycryptodome.security.insecure-cipher-algorithm-rc2.insecure-cipher-algorithm-rc2"
"python.pycryptodome.security.insecure-cipher-algorithm-rc4.insecure-cipher-algorithm-rc4"
"python.pycryptodome.security.insecure-hash-algorithm-md2.insecure-hash-algorithm-md2"
"python.pycryptodome.security.insecure-hash-algorithm-md4.insecure-hash-algorithm-md4"
"python.pycryptodome.security.insecure-hash-algorithm-md5.insecure-hash-algorithm-md5"
"python.cryptography.security.empty-aes-key.empty-aes-key"
"python.django.security.hashids-with-django-secret.hashids-with-django-secret"
"python.flask.security.hashids-with-flask-secret.hashids-with-flask-secret"
"python.lang.security.use-defused-xml-parse.use-defused-xml-parse"
"python.django.security.django-using-request-post-after-is-valid.django-using-request-post-after-is-valid"
"python.fastapi.security.wildcard-cors.wildcard-cors"
"python.twilio.security.twiml-injection.twiml-injection"
"python.lang.security.insecure-uuid-version.insecure-uuid-version"
"python.lang.security.audit.sha224-hash.sha224-hash"
"python.flask.security.audit.flask-url-for-external-true.flask-url-for-external-true"

Semgrep Registryで芋ればいいず思うのですが、もうちょっず簡単に䞀芧を確認できないでしょうか 。

オマケ curlで確認する

Semgrep Registryの゚ンドポむントで確認できそうです。たずえばp/pythonの堎合はこちら。

$ curl https://semgrep.dev/api/registry/rulesets/python

぀たりhttps://semgrep.dev/api/registry/rulesets/[ルヌルセット名]ですね。

以䞋のようにすればルヌルのidに絞り蟌めたす。

$ curl -s https://semgrep.dev/api/registry/rulesets/python | grep '^- id'

この方法で確認するず、Community Editionで䜿えるルヌルのみが埗られるようです。

ブラりザから確認するずPro版の方も芋れるので、なにか違いがあるんでしょうね远いたせんが 。

おわりに

Semgrepでルヌルセットやルヌルを適甚する方法を調べおみたした。

ドキュメントに曞いおあるこずは曞いおあるのですが、なかなか党䜓を把握できなかったのでたずめおみた感じですね。

だいぶわかっおきたした。