Python ãã®2 Advent Calendar 2018 16æ¥ç®ã®æ稿ã空ãã¦ããã®ã§ããã£ã¡ãæ¥ãéãã¦ã¾ããé£ã³è¾¼ã¿æ稿ã
ä»åã¯ãæ¨ä»ããèãããã«ãªã£ããDevSecOpsã(DevOps + Security) æ´»åã§éè¦ã«ãªã£ã¦ããããã»ãã¥ãªãã£ãã¹ããèªåã§åãããå®ç¾ããããã®ãã¼ã«ãç´¹ä»ãã¾ãã
DevSecOpsã«ã¤ãã¦ã¯ãã®ããããåç
§ã2018å¹´ã®ãã¬ã³ããããã§ãã
2018年のトレンドは、DevOpsにセキュリティを融合した「DevSecOps」 (1/2) - ITmedia エンタープライズ
èªåã»ãã¥ãªãã£ãã¹ãã«ã¯ SAST, DAST, IAST ã¨å¼ã°ãããã®ãããã¾ãã
- SAST: Static Application Security Testingï¼éçã»ãã¥ãªãã£æ¤æ»ï¼
- ã½ã¼ã¹ã³ã¼ãèªä½ã解æã»æ¤æ»ãã¦èå¼±æ§ãè¦ã¤ãåºããã®
- åãã³ã¼ãã«ãªãåã®æ®µéãã使ç¨ã§ãã
- DAST: Dynamic Application Security Testingï¼åçã»ãã¥ãªãã£æ¤æ»ï¼
- åãã¦ããã¢ããªã±ã¼ã·ã§ã³ã«å¯¾ãã¦æ§ã ãªå ¥åãä¸ãããã®çµæããã¨ã«èå¼±æ§ã®æç¡ãå¤æãã
- ãã©ãã¯ããã¯ã¹ãã¹ããªã®ã§ç¶²ç¾ æ§ã«ã¯æ¬ ãã
- IAST: Interactive Application Security Testing
- SASTã¨DASTã®åæ¹ã®ã¡ãªãããå ¼ãåãããææ³
- ã¾ãDASTã§æ¤æ»ãè¡ããçãããé¨åãSASTã§è§£æãã
ä»åã¯SASTã«ç¦ç¹ãå½ã¦ã¦ãPythonã§ä½¿ããSASTãã¼ã«2ç¹ãç´¹ä»ãã¾ãã
Bandit
Banditã¨ã¯
Bandit ã®æå³ã¯ãå±±è³ããªããã®ãã¼ãã³ã°ãã¯èª¿ã¹ã¦ã¾ãã(ï¾â§Ú¡â¦)
å
¬å¼ã®READMEãã
Banditã¯ãPythonã³ã¼ãã§å ±éã®ã»ãã¥ãªãã£åé¡ãè¦ã¤ããããã«è¨è¨ããããã¼ã«ã§ãã ãããè¡ãããã«ãBanditã¯åãã¡ã¤ã«ãå¦çããããããASTãä½æããASTãã¼ãã«å¯¾ãã¦é©åãªãã©ã°ã¤ã³ãå®è¡ãã¾ãã Banditã¯ãã¹ã¦ã®ãã¡ã¤ã«ã®ã¹ãã£ã³ãå®äºããã¨ãã¬ãã¼ããçæãã¾ãã Banditã¯ãã¨ãã¨OpenStack Security Projectå ã§éçºããããã®å¾PyCQAã«æ¹é ããã¾ããã
Bandit å ¬å¼ããã¥ã¡ã³ã:Security/Projects/Bandit
以ä¸ãBandit ã½ã¼ã¹ãªãã¸ããª(Github) ã®READMEã«ä½¿ãæ¹ã«æ²¿ã£ã¦å®æ½ãã¦ã¿ã¾ãã
installã¨å®è¡
install: pipã§installã§ãã¡ããã¾ããç°¡åã
$ pip install bandit
å®è¡: åºæ¬çã« bandit {ãã¹ã対象ã®ãã¹}
ã§ãããã»ã¨ãã©ã®ããã¸ã§ã¯ãããã£ã¬ã¯ããªæ§é ãæã£ã¦ããã¨æãã®ã§ãå帰optionã® -r
ãã¤ãã¦å®è¡ãã¾ãã
$ bandit -r {path/to/your/code}
ããã ããç°¡åã
主è¦ãªãªãã·ã§ã³
- htmlåºå
-f html
- åºåãã¡ã¤ã«ã®æå®
-o {output file}
- ãã¹ã対象ã®æå®ã»é¤å¤ã¨ãå®æ½ãã¹ãã®æå®ã»é¤å¤
.bandit
ãã¡ã¤ã«ããã¹ã対象pathã«é ç½®- targets: ãã¹ã対象ãæå®
- exclude: ãã¹ã対象ããã®é¤å¤ãæå®
/test
ãã£ã¬ã¯ããªãªã©
- skips: skipãããã¹ãã®æå®
- tests: å®æ½ãããã¹ãã®æå®
ä¾: (.bandit
)
[bandit] targets: /app exclude: /test skips: B102 tests: B101, B301
â»ãã¹ãã®IDã¯ãBandit repositoryã®READMEã«æ¸ãã¦ããã¾ã
- é¤å¤è¨å®
- Banditã§ã¯è¦åãåºããããã®è¡ãã¬ãã¥ã¼ãããå½é½æ§ã»è¨±å®¹å¯è½ã§ããå ´åã«
#nosec
ã¨ããã³ã¡ã³ãã対象ã®è¡ã«ã¤ãããã¨ã§ãbanditã®ã¬ãã¼ã対象å¤ã«ãªãã¾ãã
- Banditã§ã¯è¦åãåºããããã®è¡ãã¬ãã¥ã¼ãããå½é½æ§ã»è¨±å®¹å¯è½ã§ããå ´åã«
ä¾:
self.process = subprocess.Popen('/bin/echo', shell=True) # nosec
å®è¡çµæã¨åæ
ã¨ãããµã¼ãã¹ã®frontã³ã¼ãã解æããçµæã®ãµããª
Code scanned: Total lines of code: 2754 Total lines skipped (#nosec): 0 Run metrics: Total issues (by severity): Undefined: 0.0 Low: 0.0 Medium: 1.0 High: 0.0 Total issues (by confidence): Undefined: 0.0 Low: 0.0 Medium: 0.0 High: 1.0 Files skipped (0):
ææãããã³ã¼ãé¨åï¼severity: Medium, confidence: Highï¼ã詳ããè¦ã¦ã¿ã¾ãã
yaml_load: Use of unsafe yaml load. Allows instantiation of arbitrary objects. Consider yaml.safe_load(). Test ID: B506 Severity: MEDIUM Confidence: HIGH
yaml.load()
ã§ã¯ãªã yaml.safe_load()
ã使ããªããã¨ã®ãã¨ã
yaml.load()
ã®èå¼±æ§ã«é¢ãã¦ã¯ãã¡ãåç
§ã
ä»ããããªææã®åºãããã¸ã§ã¯ããã(severity: High, confidence: High)
The pyCrypto library and its module RSA are no longer actively maintained and have been deprecated. Consider using pyca/cryptography library. Test ID: B413 Severity: HIGH Confidence: HIGH
pyCrypto.RSA
ã pyCrypto.PKCS1_OAEP
ãªã©ã pyCryptã¢ã¸ã¥ã¼ã«èªä½ããã¯ãæ´»çºã«ã¡ã³ããã³ã¹ããã¦ããªãã®ã§ã代ããã« pyca/cryptography
ã使ããªããã¨ã®ãã¨ã RSAã®ãµã³ãã«ã³ã¼ãã¨ããã° pyCrypto
ã¨ãããããåºåã£ã¦ããã®ã§ããããããã¼ã«ããªãã¨ãªããªãæ°ã¥ãã«ãããã
以ä¸ãã»ãã¥ãªãã£åå¼·ä¼ã®ããã«ä½ã£ãèå¼±æ§ã®ãããã¨ãããã£ã¦ããWebApplicationã®ã½ã¼ã¹ã解æããçµæã§ããterminalä¸ã§ã¯è²ä»ãã§çµæã表示ãã¦ããã¦ååè¦ãããã§ãã
ã¡ãªã¿ã«ã-f html
ãªãã·ã§ã³ãä»ãã¦å®è¡ããã¨ãä¸è¨ã®ãããªåºåãå¾ããã¾ãã
Pyt
Pytã¨ã¯
å ¬å¼ã®READMEãã
çè«çåºç¤ï¼å¶å¾¡ããã¼ã°ã©ããä¸åç¹è§£æããã¼ã¿ããã¼è§£æï¼ã«åºã¥ãPython Webã¢ããªã±ã¼ã·ã§ã³ã®éç解æ
ç¹å¾´:
- ã³ãã³ãã¤ã³ã¸ã§ã¯ã·ã§ã³
- SSRF
- SQLã¤ã³ã¸ã§ã¯ã·ã§ã³
- XSS
- ãã£ã¬ã¯ããªãã©ãã«
ãªã©ã®æ¤åº
Pytã¯Banditã¨ã¯ç°ãªããWebã¢ããªã±ã¼ã·ã§ã³ã«ç¹åãã¦ãã¾ãããã®ãããä¸è¬çãªWebã¢ããªã±ã¼ã·ã§ã³æ©è½ãæãã routing æ©è½ãªã©ãããã·ã¹ãã ãåæã«ãã¦ãã¾ãã
æ示çã«å¯¾å¿ãã¦ããWebFrameworkã®ã¯ãFlask, Djangoã§ããããã®ä»ã®FWã -a ãªãã·ã§ã³ã¨è¨å®ãã¡ã¤ã«ã®è¨è¿°ã«ããå©ç¨å¯è½ã§ãã
installã¨å®è¡
insatll: ãã¡ããpipã³ãã³ãã§ã¤ã³ã¹ãã¼ã«ã§ãã¾ãã
$ pip install python-taint
setting: Banditããã¡ãã£ã¨è¤éã
ã¾ãã¯ä½¿ç¨ãã¦ããWebFrameworkãé¸æãã¾ãã default 㯠Flaskã§ããWebFWã¯
-a
optionã§é¸æãã¾ãã詳細ã¯ãã¡ã- flask: none
- django:
-a D
â»å¤æåºæºã¯ãªã³ã¯å åç § - Every:
-a E
â»å¤æåºæºã¯ãªã³ã¯å åç § - Pylons:
-a P
â»å¤æåºæºã¯ãªã³ã¯å åç §
ä»åã¯Flaskãªã®ã§ãªãã·ã§ã³ç¡ãã§å®è¡ãã¾ãã
ãã¹ã対象ã®è¨å®ãã¡ã¤ã«ãã«ã¹ã¿ãã¤ãºã»è¨å®ãã¾ã
- defaultã§ã¯ãã¡ãã使ããã¾ã
- 対象ã®methodã®åæ¨é¸æãããã§ãã¯å 容ãã«ã¹ã¿ãã¤ãºã§ãã¾ã
æ¤åºãããé¢æ°ãã«ã¹ã¿ãã¤ãºãã
- defaultã§ã¯ãã¡ãã使ããã¾ã
ä¸è¨ã®ããã«ãã¿ã¼ã²ãã対象ã»å¯¾è±¡å¤ã®directoryãé¤å¤è¨å®ã¯banditã¨åããè¨å®å¯è½ã§ãã
å®è¡: ãã¡ãããªãã·ã§ã³ç¡ãã ã¨ã·ã³ãã«ã§ã pyt {ãã¹ã対象ã®ãã¹}
ã§ãã
$ pyt (-a ADAPTOR) {path/to/your/code}
-a ãªãã·ã§ã³ã¯ä½¿ç¨ãã¦ããWebFWã«ãã£ã¦ã¯å¿ é ãªã®ã§æ³¨æã§ãã
å®è¡çµæã¨åæ
ã¨ãããµã¼ãã¹ã®frontã³ã¼ãã解æããçµæ
$ pyt -r ./app/front No vulnerabilities found.
ä½ãæ¤åºããã¾ããã§ããã
ãªããªãææãåºã¦ããããã¸ã§ã¯ãããªãã£ããããå
ç¨ã使ç¨ããSQL Injection ã®èå¼±æ§ãããã¨ããã£ã¦ããprojectã解æã
$ pyt -r ./web_1/sqli_1/flask 2 vulnerabilities found: Vulnerability 1: File: ./hello.py > User input at line 19, source "form[": name = request.form['Name'] Reassigned in: File: ./hello.py > Line 23: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password) File: ./hello.py > Line 23: query = ~call_3 File: ./hello.py > reaches line 25, sink "execute(": ~call_4 = ret_cursor.execute(query) This vulnerability is unknown due to: Label: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password) Vulnerability 2: File: ./hello.py > User input at line 20, source "form[": password = request.form['Password'] Reassigned in: File: ./hello.py > Line 23: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password) File: ./hello.py > Line 23: query = ~call_3 File: ./hello.py > reaches line 25, sink "execute(": ~call_4 = ret_cursor.execute(query) This vulnerability is unknown due to: Label: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)
2ã¤æ¤åºããã¾ããï¼ã¡ãã£ã¨é·ãã¦ãããè¾ãã
1ã¤ç®ã¨2ã¤ç®ã¯ name
ã password
ãã®éããªã®ã§ãï¼ã¤ç®ãä¸ããèªã¿è§£ãã¨ã
> User input at line 20, source "form[": password = request.form['Password']
ããã§Userããã®å ¥åãããã§ããã
Reassigned in: > Line 23: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)
ããã§ä»£å ¥ããã¦ãã§ããã
> reaches line 25, sink "execute(": ~call_4 = ret_cursor.execute(query)
ããããããã¾ã§(ã¦ã¼ã¶ã¼ã®å ¥åã)å°éãã¡ããã§ããã
This vulnerability is unknown due to: Label: ~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)
ãã®èå¼±æ§ï¼ã®ã«ãã´ã©ã¤ãºï¼ã¯ã以ä¸ã®ç®æãåå ã§ä¸æã§ãã
ãããªæãã§ããããã
確ãã« SQL Injection ãèµ·ããåå ã¨ãªã£ã¦ããç®æããªã¹ãã¢ããããã¦ãã¾ãããå
·ä½çãªçç±ã»ä¿®æ£æ¡ã¯åºåããã¾ããã§ããã
pytã«ã¯htmlå½¢å¼ã®ã¬ãã¼ãã¯ãªããããªã®ã§ãjsonå½¢å¼ã§åºåãã¦ã¿ã¾ããï¼-j
ãªãã·ã§ã³ã追å ãã¦å®è¡ããã ãï¼
{ "generated_at": "2018-12-21T05:32:30Z", "vulnerabilities": [ { "source": { "label": "name = request.form['Name']", "line_number": 19, "path": "./hello.py" }, "source_trigger_word": "form[", "sink": { "label": "~call_4 = ret_cursor.execute(query)", "line_number": 25, "path": "./hello.py" }, "sink_trigger_word": "execute(", "type": "UnknownVulnerability", "reassignment_nodes": [ { "label": "~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)", "line_number": 23, "path": "./hello.py" }, { "label": "query = ~call_3", "line_number": 23, "path": "./hello.py" } ], "unknown_assignment": { "label": "~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)", "line_number": 23, "path": "./hello.py" } }, { "source": { "label": "password = request.form['Password']", "line_number": 20, "path": "./hello.py" }, "source_trigger_word": "form[", "sink": { "label": "~call_4 = ret_cursor.execute(query)", "line_number": 25, "path": "./hello.py" }, "sink_trigger_word": "execute(", "type": "UnknownVulnerability", "reassignment_nodes": [ { "label": "~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)", "line_number": 23, "path": "./hello.py" }, { "label": "query = ~call_3", "line_number": 23, "path": "./hello.py" } ], "unknown_assignment": { "label": "~call_3 = ret_'SELECT * FROM users WHERE name='{name}' AND password='{password}''.format(name=name, password=password)", "line_number": 23, "path": "./hello.py" } } ] }
人ã®ç®ã§è¦ãã¶ãã«ã¯ãç¹ã«èªã¿ãããã¯å¤ããã¾ããã§ããâ¦ãå®è¡çµæãã¹ã¯ãªããã§è§£æããããªããããã¶ãã«ã¯ä½¿ãããããã§ãã
ããä¸ã¤ãã£ã¦ã¿ã¾ãã次㯠XSS ã®èå¼±æ§ãããã¨ããã£ã¦ããä¸è¨ã®ã½ã¼ã¹ã§ãã
$ pyt -r ./web_1/xss_1/flask 1 vulnerability found: Vulnerability 1: File: ./hello.py > User input at line 14, source "form[": name = request.form['Name'] File: ./hello.py > reaches line 17, sink "render_template(": ~call_2 = ret_render_template('xss_form.html', name=name, secret=secret)
ç¡äºæ¤åºããã¾ãããä»å㯠14è¡ç®ã§ã¦ã¼ã¶ã¼ã®ã¤ã³ããããåãä»ãããã®ãã17è¡ç®ã®renderé¨åã«ç´æ¥å°éãã¦ãããã¨ãææããã¦ããããã§ãã
ã¤ãã§ã«æå¾ã¯ãã¹ãã©ãã¼ãµã«ã®èå¼±æ§ããããµã¼ãã¹ã
$ pyt -r ./web_1/directory_1/flask 1 vulnerability found: Vulnerability 1: File: ./hello.py > User input at line 16, source "request.args.get(": ~call_1 = ret_request.args.get('image') Reassigned in: File: ./hello.py > Line 16: image = ~call_1 File: ./hello.py > Line 19: ~call_4 = ret_os.path.join(~call_5, 'static', image) File: ./hello.py > reaches line 19, sink "send_file(": ~call_3 = ret_send_file(~call_4)
ä¼¼ããããªæãã§ãããä»åã¯URLã®Pathãåå¾ããé¨åã User input ã®å¯è½æ§ã®ããå ´æã¨ãã¦ææããã¦ãã¾ãã
ã¾ã¨ã
ä»åã¯Pythonã®SASTãã¼ã«ã§ãã Bandit 㨠Pyt ãç´¹ä»ãã¾ããã
Banditã®ã»ããçµæã®åºåãè¦ããããå½¢å¼ã csv, custom, html, json, screen, txt, xml, yaml ã¨ãã¡ããã¡ãé¸æè¢ããããããã±ã£ã¨å§ããã«ã¯ã¨ã£ã¤ãããããã§ããåºåå
容ããPytã§ã¯åºã¦ããªãã£ã SQL Injection
ãªã©å
·ä½çãªèå¼±æ§ã®ååãææããã¦ãã¾ããã
ä¸æ¹ãåãã³ã¼ãã解æããã¨ãããPyt ã§ææã®ãã£ãå
容㧠Bandit ã§ãæ¾ããªãã£ããã®ãããã¾ãã (XSSããã£ã¬ã¯ããªãã©ãã¼ãµã«)ãSASTãã¼ã«ã¯è¤æ°ã®ãã¼ã«ãå°å
¥ãããã¨ãèå¼±æ§ã®æ©æçºè¦ã«å½¹ç«ã¡ã¾ããPytã¯Banditã¨æ¯è¼ãã¦åºåçµæãèªã¿è§£ãã®ã«è¨ç·´ãããããã§ãããBanditã¨ã¯éã£ããã¸ãã¯ã§æ¤æ»ãè¡ã£ã¦ãã¾ãã
ä»åã®2ã¤ã®ãã¼ã«ã¯installããå®è¡ã¾ã§å°å
¥éå£ãå°ãªãä¸ã«å®è¡æéãããçããã¨ãããä½µç¨ããã®ããå§ãã§ãã
SASTãã¼ã«ã¯CIã¨å¤§å¤ç¸æ§ããããcommitãpushãã¨ã«UTããã©ã¼ããããã§ãã¯ãªã©ã¨åããã¦å®æ½ãããããã¨æãã¾ããã¿ãªãããæ¯é2018å¹´ã®ãã¬ã³ãã§ãããDevSecOpsãã«ä¹ã£ãã£ã¦ãSASTãã¼ã«ãéçºã»CIã«å°å ¥ãã¦ã¿ã¾ãããï¼
åèãªã³ã¯
- GitHub - PyCQA/bandit: Bandit is a tool designed to find common security issues in Python code.
- GitHub - python-security/pyt: A Static Analysis Tool for Detecting Security Vulnerabilities in Python Web Applications
- 開発工程に脆弱性検査の組み込みを、クラウドサービスで実現するHP:カジュアルに作れるからこそ気にしたい、Webアプリの脆弱性 - @IT
- Developers Summit 2017 Summer【C-6】CIにおけるセキュリティテストの組み込み方について 聴講メモ - dimeizaのブログ
- GitHub - kusuwada/security_handson: for Security Hanson.
- ã»ãã¥ãªãã£åå¼·ä¼ã®ããã«ä½ã£ãèå¼±æ§ã®ãããã¨ãããã£ã¦ããWebApplicationã®ã½ã¼ã¹