This introduces a number of secure development practices that were written by the OSSG during the mid-cycle meetup of 2015. Credit goes to the original authors and editors of this content: Dave Belcher (HP) Eric Brown (VMWare) Doug Chivers (HP) Rob Clarke (HP) Nathaniel Dillon (HP) Lucas Fisher (Was Nebula) Jamie Finnigan (HP) Rob Fletcher (Uber) Tim Kelsey (HP) Brant Knudson (IBM) Paul McMillan (Was Nebula) Travis McPeak (HP) Grant Murphy (HP) The following is an attempt to track the origins on this content as it was developed. It is not a complete version history but indicates the initial import of the content into respective repositories prior to ending up here. Hopefully this will be enough to track the changes and contributions made by members of the OpenStack community. { "origins": [ { "author": "Travis McPeak (HP)", "file": "doc/source/guidelines/dg_apply-restrictive-file-permissions.rst", "history": [ { "commit": "d5f6ad970ec24564cfaffc13dba26b0006841d5b", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "c7d0e14e9a71fa9bbe301aa76a8adcc55ade52de", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Lucas Fisher (Nebula)", "file": "doc/source/guidelines/dg_avoid-dangerous-input-parsing-libraries.rst", "history": [ { "commit": "9f12b0bacc7bf207df5615dce39940aaede66e17", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "9b4181fe3c2e5451ebf65b99b05fe169b6eda63c", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Paul McMillan (Nebula)", "comment": "The file was not renamed correctly!", "file": "doc/source/guidelines/dg_avoid-shell-true.rst", "history": [ { "commit": "ef6338caa2a6f5cfb67dd2d77a38574d45ae5d2c", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "c7ade476015c1b0fbb1b100b990a10e8373027c2", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Grant Murphy (HP)", "file": "doc/source/guidelines/dg_avoid-unvalidated-redirects.rst", "history": [ { "commit": "2f0c954bd4f25a06b8a1439739d494c3a9d0c2de", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "8fb7804da189c95e9bcd2b19b516077b8fb6a44a", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Dave Belcher (HP)", "file": "doc/source/guidelines/dg_cross-site-request-forgery-csrf.rst", "history": [ { "commit": "34146ded7f5c8ca3b0be29c17b30fb887a47b955", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "688a73070e52a693f1fc7b827cfbfe1d03bd7f9c", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Dave Belcher (HP)", "file": "doc/source/guidelines/dg_cross-site-scripting-xss.rst", "history": [ { "commit": "f4261162a2b07df282fbfab68245b23c39f46fb9", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "e8a3cf91778081e0c822277951c0f5cbc6293c21", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Rob Clarke (HP)", "file": "doc/source/guidelines/dg_move-data-securely.rst", "history": [ { "commit": "5d57e38c71ec7fd9113bb5574c143b4b146b95d5", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "6d266e56a1b4b746deab7b26d6b8bf96774dca72", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Tim Kelsey", "file": "doc/source/guidelines/dg_parameterize-database-queries.rst", "history": [ { "commit": "70969ec41f9ce5de47090ac7a5cb4e303671b756", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Eric Brown (VMware)", "file": "doc/source/guidelines/dg_protect-sensitive-data-in-files.rst", "history": [ { "commit": "038d65e6fd8c17dffa28f55c99e218d09802f5ec", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "8094050151347ac83b6a05c5895dc9f670b70c29", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Eric Brown (VMware)", "file": "doc/source/guidelines/dg_validate-certificates.rst", "history": [ { "commit": "f74fecc0360a9f9c6984d821b128c4830bd71b0f", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "2ffd29660d9f48079ab1c9a0de170eb660ba22fe", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Lucas Fisher (Nebula)", "file": "doc/source/guidelines/dg_rootwrap-recommendations-and-plans.rst", "history": [ { "commit": "bd5a51411420fd70ee410ff72cb396287ce0c60e", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "6a13d1ecd8ec73f7038c8e3238e24ac32ac60e58", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Jamie Finnigan (HP)", "file": "doc/source/guidelines/dg_strong-crypto.rst", "history": [ { "commit": "cefac3ea2ab56e4e7c6238f69f63b7f88d1b58ec", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "4d430b4cf18687b322c931f1bddf8147da853bb5", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Eric Brown (VMware)", "file": "doc/source/guidelines/dg_use-oslo-rootwrap-securely.rst", "history": [ { "commit": "921f9fc2d949a6a48ba8c936a81b7f15024e50f8", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "3fc0ca5df47cd118d111e6020e1f1101b3c4fbc3", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Paul McMillan (Nebula)", "file": "doc/source/guidelines/dg_use-subprocess-securely.rst", "history": [ { "commit": "7a305304d600b1e0d868e1fa174d31bdb460c041", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "f4ccd51a10ca0380737d6be8bc5ae6c677a60b39", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "Grant Murphy (HP)", "file": "doc/source/guidelines/dg_using-file-paths.rst", "history": [ { "commit": "f2d93147e7b8e30750b2f6ad548a1478f74e4489", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "d8593eaea31e9d4756005555dfb85f41013ee6d4", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] }, { "author": "b005cc2968ecbcdbf7cc455ecac1e8ede2b2fa21", "file": "doc/source/guidelines/dg_using-temporary-files-securely.rst", "history": [ { "commit": "cf1981af0bba72558b8cfa349d841ceee4722b7f", "id": "1", "repo": "git://github.com/hyakuhei/OSSG-Security-Practices" }, { "commit": "", "id": "2", "repo": "github.com/openstack-security/Developer-Guidance" } ] } ] } Change-Id: I8ae30f526523860c0fc069cf1e683f1b8a69eb4d
4.6 KiB
Avoid dangerous file parsing and object serialization libraries
Many common libraries that are often used for reading configuration files and deserializing objects are very dangerous because they can allow execution of arbitrary code. By default, libraries such as PyYAML and pickle do not provide strong separation of data and code, and thus allow code to be embedded inside the input.
Often the input to these libraries is untrusted or only partially trusted. These unsafe inputs can come from configuration files or be provided via REST APIs. For example, we often use YAML for configuration files but YAML files can also contain embedded Python code. This may provide an attacker with a method to execute code.
Many, but not all, of these libraries, offer safe interfaces that disable features that enable code execution. You always want to use the safe functions to load input. Often the obvious function to use is not the safe one and we should check the documentation for libraries not covered here.
Python Libraries
We often use YAML, pickle, or eval to load data into our Python programs, but this is dangerous. PyYAML has a safe way to load code, but pickle and eval do not.
Module | Problem | Use | Avoid |
---|---|---|---|
PyYAML | Allows creating arbitrary Python objects. | yaml.safe_load | yaml.load |
pickle | Allows creating arbitrary Python objects. | Do not use | pickle.load, pickle.loads |
cPickle | Allows creating arbitrary Python objects. | Do not use | cPickle.load, cPickle.loads |
eval | Runs all input as Python code | Do not use | eval |
exec | Runs all input as Python code (Python 3.x) | Do not use | exec |
Incorrect
yaml.load is the obvious function to use but it is dangerous:
import yaml
import pickle
= '''
conf_str !!python/object:__main__.AttackerObj
key: 'value'
'''
= yaml.load(conf_str) conf
Using pickle or cPickle with untrusted input can result in arbitrary code execution.
import pickle
import cPickle
= "cos\nsystem\n(S'cat /etc/passwd'\ntR.'\ntR."
user_input # results in code execution
cPickle.loads(user_input) # results in code execution pickle.loads(user_input)
Similarly eval and exec are difficult to use safely with input that comes from an untrusted source.
= "os.system('cat /etc/passwd')"
user_input eval(user_input) # execute python expressions
= "import os; os.system('cat /etc/passwd')"
user_input exec(user_input) # execute _any_ python code
Correct
Here we use PyYAMLs safe YAML loading function:
import yaml
= '''
conf_str - key: 'value'
- key: 'value'
'''
= yaml.safe_load(conf_str) conf
There is no safe alternative for pickle.load. However in most cases using pickle for serialization of data objects is something that can be avoided altogether.
Consequences
- Anyone that can control the input passed to dangerous libraries can gain arbitrary code execution on the system running the dangerous library.