Skip to content

Commit

Permalink
Update DUO130 to support hashlib constructor usedforsecurity=False pa…
Browse files Browse the repository at this point in the history
…ram (#42)

Support for this arrived in Python 3.9, but this rule should be fully
backwards-compatible with older versions of Python.
  • Loading branch information
djmattyg007 committed May 16, 2022
1 parent f282d31 commit ce0b19c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- Support `usedforsecurity=False` parameter to hashlib constructors ([#39](https://github.com/dlint-py/dlint/issues/39))

## [0.12.0] - 2021-10-27
### Added
Expand Down
30 changes: 21 additions & 9 deletions dlint/linters/bad_hashlib_use.py
Expand Up @@ -7,10 +7,12 @@
unicode_literals,
)

from .helpers import bad_module_attribute_use
from .helpers import bad_kwarg_use

from .. import tree

class BadHashlibUseLinter(bad_module_attribute_use.BadModuleAttributeUseLinter):

class BadHashlibUseLinter(bad_kwarg_use.BadKwargUseLinter):
"""This linter looks for unsafe use of the Python "hashlib" module. Use of
md5|sha1 is known to have hash collision weaknesses.
"""
Expand All @@ -20,10 +22,20 @@ class BadHashlibUseLinter(bad_module_attribute_use.BadModuleAttributeUseLinter):
_error_tmpl = 'DUO130 insecure use of "hashlib" module'

@property
def illegal_module_attributes(self):
return {
'hashlib': [
'md5',
'sha1',
],
}
def kwargs(self):
def missing_or_true(call, kwarg_name):
return (
tree.kwarg_not_present(call, kwarg_name)
or tree.kwarg_true(call, kwarg_name)
)

bad_hash_algorithms = {"md5", "sha1"}

return [
{
"module_path": f"hashlib.{hash_algorithm}",
"kwarg_name": "usedforsecurity",
"predicate": missing_or_true,
}
for hash_algorithm in bad_hash_algorithms
]
5 changes: 5 additions & 0 deletions docs/linters/DUO130.md
Expand Up @@ -25,6 +25,10 @@ import hashlib
sha256_hashed = hashlib.sha256(b"data").hexdigest()
sha512_hashed = hashlib.sha512(b"data").hexdigest()
blake2b_hashed = hashlib.blake2b(b"data").hexdigest()

# Only supported in Python 3.9 and above
md5_hashed = hashlib.md5(b"data", usedforsecurity=False).hexdigest()
sha1_hashed = hashlib.sha1(b"data", usedforsecurity=False).hexdigest()
# ...
```

Expand All @@ -35,3 +39,4 @@ Some algorithms have known hash collision weaknesses.
## Exceptions

* Compatibility with systems that can only use MD5 or SHA1 and are not under your control
* Use cases that are related to checksumming, rather than cryptography.
50 changes: 50 additions & 0 deletions tests/test_bad_hashlib_use.py
Expand Up @@ -45,6 +45,56 @@ def test_bad_hashlib_usage(self):

assert result == expected

def test_hashlib_used_for_security(self):
python_node = self.get_ast_node(
"""
import hashlib
var = 'echo "TEST"'
m1 = hashlib.md5(usedforsecurity=True)
m2 = hashlib.sha1(usedforsecurity=True)
"""
)

linter = dlint.linters.BadHashlibUseLinter()
linter.visit(python_node)

result = linter.get_results()
expected = [
dlint.linters.base.Flake8Result(
lineno=6,
col_offset=5,
message=dlint.linters.BadHashlibUseLinter._error_tmpl
),
dlint.linters.base.Flake8Result(
lineno=7,
col_offset=5,
message=dlint.linters.BadHashlibUseLinter._error_tmpl
),
]

assert result == expected

def test_hashlib_not_used_for_security(self):
python_node = self.get_ast_node(
"""
import hashlib
var = 'echo "TEST"'
m1 = hashlib.md5(usedforsecurity=False)
m2 = hashlib.sha1(usedforsecurity=False)
"""
)

linter = dlint.linters.BadHashlibUseLinter()
linter.visit(python_node)

result = linter.get_results()

assert len(result) == 0


if __name__ == "__main__":
unittest.main()

0 comments on commit ce0b19c

Please sign in to comment.