Skip to content
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 check for "requests" calls without timeout #743

Merged
merged 20 commits into from Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions bandit/core/issue.py
Expand Up @@ -25,6 +25,7 @@ class Cwe:
BROKEN_CRYPTO = 327
INSUFFICIENT_RANDOM_VALUES = 330
INSECURE_TEMP_FILE = 377
UNCONTROLLED_RESOURCE_CONSUMPTION = 400
DESERIALIZATION_OF_UNTRUSTED_DATA = 502
MULTIPLE_BINDS = 605
IMPROPER_CHECK_OF_EXCEPT_COND = 703
Expand Down
71 changes: 71 additions & 0 deletions bandit/plugins/request_without_timeout.py
@@ -0,0 +1,71 @@
# SPDX-License-Identifier: Apache-2.0

ericwb marked this conversation as resolved.
Show resolved Hide resolved
r"""
=======================================
B113: Test for missing requests timeout
=======================================

This plugin test checks for ``requests`` calls without a timeout specified.

Nearly all production code should use this parameter in nearly all requests,
Failure to do so can cause your program to hang indefinitely.

When request methods are used without the timeout parameter set,
Bandit will return a MEDIUM severity error.


:Example:

.. code-block:: none

>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
ericwb marked this conversation as resolved.
Show resolved Hide resolved
Location: examples/requests-missing-timeout.py:3:0
More Info: https://bandit.readthedocs.io/en/latest/plugins/b113_request_without_timeout.html
ericwb marked this conversation as resolved.
Show resolved Hide resolved
2
3 requests.get('https://gmail.com')
4 requests.get('https://gmail.com', timeout=None)

--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call with timeout set to None
Severity: Medium Confidence: Low
Location: examples/requests-missing-timeout.py:4:0
More Info: https://bandit.readthedocs.io/en/latest/plugins/b113_request_without_timeout.html
ericwb marked this conversation as resolved.
Show resolved Hide resolved
3 requests.get('https://gmail.com')
4 requests.get('https://gmail.com', timeout=None)
5 requests.get('https://gmail.com', timeout=5)

.. seealso::

- https://2.python-requests.org/en/master/user/quickstart/#timeouts

mschfh marked this conversation as resolved.
Show resolved Hide resolved
.. versionadded:: 1.7.5

""" # noqa: E501

ericwb marked this conversation as resolved.
Show resolved Hide resolved
import bandit
from bandit.core import test_properties as test
ericwb marked this conversation as resolved.
Show resolved Hide resolved


@test.checks("Call")
@test.test_id("B113")
def request_without_timeout(context):
http_verbs = ("get", "options", "head", "post", "put", "patch", "delete")
if ("requests" in context.call_function_name_qual and
context.call_function_name in http_verbs):
ericwb marked this conversation as resolved.
Show resolved Hide resolved
# check for missing timeout
if context.check_call_arg_value("timeout") is None:
issue = bandit.Issue(
ericwb marked this conversation as resolved.
Show resolved Hide resolved
severity=bandit.MEDIUM,
confidence=bandit.LOW,
text="Requests call without timeout"
ericwb marked this conversation as resolved.
Show resolved Hide resolved
)
return issue
ericwb marked this conversation as resolved.
Show resolved Hide resolved
# check for timeout=None
if context.check_call_arg_value("timeout", "None"):
issue = bandit.Issue(
ericwb marked this conversation as resolved.
Show resolved Hide resolved
severity=bandit.MEDIUM,
confidence=bandit.LOW,
text="Requests call with timeout set to None"
ericwb marked this conversation as resolved.
Show resolved Hide resolved
)
return issue
ericwb marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions doc/source/plugins/b113_request_without_timeout.rst
@@ -0,0 +1,5 @@
-----------------------------
B113: request_without_timeout
-----------------------------

.. automodule:: bandit.plugins.request_without_timeout
2 changes: 1 addition & 1 deletion examples/httpoxy_cgihandler.py
Expand Up @@ -2,7 +2,7 @@
import wsgiref.handlers

def application(environ, start_response):
r = requests.get('https://192.168.0.42/private/api/foobar')
r = requests.get('https://192.168.0.42/private/api/foobar', timeout=30)
start_response('200 OK', [('Content-Type', 'text/plain')])
return [r.content]

Expand Down
23 changes: 23 additions & 0 deletions examples/requests-missing-timeout.py
@@ -0,0 +1,23 @@
import requests

requests.get('https://gmail.com')
requests.get('https://gmail.com', timeout=None)
requests.get('https://gmail.com', timeout=5)
requests.post('https://gmail.com')
requests.post('https://gmail.com', timeout=None)
requests.post('https://gmail.com', timeout=5)
requests.put('https://gmail.com')
requests.put('https://gmail.com', timeout=None)
requests.put('https://gmail.com', timeout=5)
requests.delete('https://gmail.com')
requests.delete('https://gmail.com', timeout=None)
requests.delete('https://gmail.com', timeout=5)
requests.patch('https://gmail.com')
requests.patch('https://gmail.com', timeout=None)
requests.patch('https://gmail.com', timeout=5)
requests.options('https://gmail.com')
requests.options('https://gmail.com', timeout=None)
requests.options('https://gmail.com', timeout=5)
requests.head('https://gmail.com')
requests.head('https://gmail.com', timeout=None)
requests.head('https://gmail.com', timeout=5)
29 changes: 14 additions & 15 deletions examples/requests-ssl-verify-disabled.py
@@ -1,21 +1,20 @@
import httpx
import requests


requests.get('https://gmail.com', verify=True)
requests.get('https://gmail.com', verify=False)
requests.post('https://gmail.com', verify=True)
requests.post('https://gmail.com', verify=False)
requests.put('https://gmail.com', verify=True)
requests.put('https://gmail.com', verify=False)
requests.delete('https://gmail.com', verify=True)
requests.delete('https://gmail.com', verify=False)
requests.patch('https://gmail.com', verify=True)
requests.patch('https://gmail.com', verify=False)
requests.options('https://gmail.com', verify=True)
requests.options('https://gmail.com', verify=False)
requests.head('https://gmail.com', verify=True)
requests.head('https://gmail.com', verify=False)
requests.get('https://gmail.com', timeout=30, verify=True)
requests.get('https://gmail.com', timeout=30, verify=False)
requests.post('https://gmail.com', timeout=30, verify=True)
requests.post('https://gmail.com', timeout=30, verify=False)
requests.put('https://gmail.com', timeout=30, verify=True)
requests.put('https://gmail.com', timeout=30, verify=False)
requests.delete('https://gmail.com', timeout=30, verify=True)
requests.delete('https://gmail.com', timeout=30, verify=False)
requests.patch('https://gmail.com', timeout=30, verify=True)
requests.patch('https://gmail.com', timeout=30, verify=False)
requests.options('https://gmail.com', timeout=30, verify=True)
requests.options('https://gmail.com', timeout=30, verify=False)
requests.head('https://gmail.com', timeout=30, verify=True)
requests.head('https://gmail.com', timeout=30, verify=False)

httpx.request('GET', 'https://gmail.com', verify=True)
httpx.request('GET', 'https://gmail.com', verify=False)
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Expand Up @@ -60,6 +60,9 @@ bandit.plugins =
# bandit/plugins/crypto_request_no_cert_validation.py
request_with_no_cert_validation = bandit.plugins.crypto_request_no_cert_validation:request_with_no_cert_validation

# bandit/plugins/request_without_timeout.py
request_without_timeout = bandit.plugins.request_without_timeout:request_without_timeout

# bandit/plugins/exec.py
exec_used = bandit.plugins.exec:exec_used

Expand Down
8 changes: 8 additions & 0 deletions tests/functional/test_functional.py
Expand Up @@ -393,6 +393,14 @@ def test_requests_ssl_verify_disabled(self):
}
self.check_example("requests-ssl-verify-disabled.py", expect)

def test_requests_without_timeout(self):
'''Test for the `requests` library missing timeouts.'''
ericwb marked this conversation as resolved.
Show resolved Hide resolved
expect = {
"SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 14, "HIGH": 0},
"CONFIDENCE": {"UNDEFINED": 0, "LOW": 14, "MEDIUM": 0, "HIGH": 0}
ericwb marked this conversation as resolved.
Show resolved Hide resolved
}
self.check_example("requests-missing-timeout.py", expect)

def test_skip(self):
"""Test `#nosec` and `#noqa` comments."""
expect = {
Expand Down