-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add input linter when asking for password #54
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#!/usr/bin/env python | ||
|
||
from . import base | ||
|
||
|
||
class InputPasswordUseLinter(base.BaseLinter): | ||
"""This linter looks for use of the Python "input" function with a string | ||
argument containing the word "password" in any format. | ||
""" | ||
off_by_default = False | ||
|
||
_code = 'DUO139' | ||
_error_tmpl = 'DUO139 avoid using "input" to ask for password' | ||
|
||
def visit_Call(self, node): | ||
|
||
if (node.func.id == "input"): | ||
value = self._get_arg_or_kwarg(node) | ||
|
||
if "password" in value.lower(): | ||
self.results.append( | ||
base.Flake8Result( | ||
lineno=node.lineno, | ||
col_offset=node.col_offset, | ||
message=self._error_tmpl | ||
) | ||
) | ||
|
||
def _get_arg_or_kwarg(self, node): | ||
if node.args: | ||
return node.args[0].value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should also check that |
||
if node.keywords: | ||
return node.keywords[0].value.value |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ Dlint uses a simple, folder-based hierarchy written in [Markdown](https://en.wik | |
- [`DUO136` `BadXmlsecModuleAttributeUseLinter` insecure "xmlsec" attribute use](https://github.com/dlint-py/dlint/blob/master/docs/linters/DUO136.md) | ||
- [`DUO137` `BadItsDangerousKwargUseLinter` insecure "itsdangerous" use allowing empty signing](https://github.com/dlint-py/dlint/blob/master/docs/linters/DUO137.md) | ||
- [`DUO138` `BadReCatastrophicUseLinter` catastrophic "re" usage - denial-of-service possible](https://github.com/dlint-py/dlint/blob/master/docs/linters/DUO138.md) | ||
- todo | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this needs a bump 👍 |
||
|
||
# FAQs | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# DUO139 | ||
|
||
This linter searches for use of the built-in `input` function with some form of the string | ||
"password" as an argument to the function. | ||
|
||
## Problematic code | ||
|
||
```python | ||
input("password: ") | ||
input("Password: ") | ||
input("PASSWORD") | ||
``` | ||
|
||
## Correct code | ||
|
||
```python | ||
import getpass | ||
|
||
getpass.getpass() | ||
``` | ||
|
||
## Rationale | ||
|
||
[getpass](https://docs.python.org/3.7/library/getpass.html) safely asks for a password without echoing the input by default. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env python | ||
|
||
import pytest | ||
import unittest | ||
|
||
import dlint | ||
|
||
|
||
@pytest.mark.parametrize("code", [ | ||
"""input('enter your name:')""", | ||
"""input = 1""", | ||
"""password = 'something'""", | ||
]) | ||
def test_input_password_not_used(code): | ||
python_node = dlint.test.base.get_ast_node(code) | ||
|
||
linter = dlint.linters.InputPasswordUseLinter() | ||
linter.visit(python_node) | ||
|
||
result = linter.get_results() | ||
expected = [] | ||
|
||
assert result == expected | ||
|
||
|
||
@pytest.mark.parametrize("code", [ | ||
"""input('enter your password:')""", | ||
"""input('enter your PASSWORD:')""", | ||
# unable to detect if the intent wasn't to ask for password because word 'password' is present | ||
"""input('Please enter your name. Please do not enter your password')""", | ||
"""input(prompt='enter your PASSWORD:')""", | ||
]) | ||
def test_input_password_bad(code): | ||
python_node = dlint.test.base.get_ast_node(code) | ||
|
||
linter = dlint.linters.InputPasswordUseLinter() | ||
linter.visit(python_node) | ||
|
||
result = linter.get_results() | ||
|
||
expected = [ | ||
dlint.linters.base.Flake8Result( | ||
lineno=1, | ||
col_offset=0, | ||
message=dlint.linters.InputPasswordUseLinter._error_tmpl | ||
) | ||
] | ||
|
||
assert result == expected | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to include the remediation in the message if it's short enough. How does this sound?
DUO139 avoid using "input" to ask for password, prefer "getpass.getpass"