Skip to content

Commit

Permalink
Reduce rule scope
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jan 5, 2024
1 parent 06f2b88 commit 8f9e174
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 166 deletions.
17 changes: 0 additions & 17 deletions crates/ruff_linter/resources/test/fixtures/flake8_bandit/S502.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,6 @@
Context(method=SSL.SSLv3_METHOD) # S502
Context(method=SSL.TLSv1_METHOD) # S502


def func():
pass


func(ssl_version=ssl.PROTOCOL_SSLv2) # S502
func(ssl_version=ssl.PROTOCOL_SSLv3) # S502
func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
func(method=SSL.SSLv2_METHOD) # S502
func(method=SSL.SSLv23_METHOD) # S502
func(method=SSL.SSLv3_METHOD) # S502
func(method=SSL.TLSv1_METHOD) # S502

wrap_socket(ssl_version=ssl.PROTOCOL_TLS_CLIENT) # OK
SSL.Context(method=SSL.TLS_SERVER_METHOD) # OK
func(ssl_version=ssl.PROTOCOL_TLSv1_2) # OK




Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr, ExprCall};
use ruff_python_semantic::analyze::typing::find_assigned_value;
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;

/// ## What it does
/// Checks for calls to Python methods with parameters that indicate the used broken SSL/TLS
/// protocol versions.
/// Checks for function calls with parameters that indicate the use of insecure
/// SSL and TLS protocol versions.
///
/// ## Why is this bad?
/// Several highly publicized exploitable flaws have been discovered in all versions of SSL and
/// early versions of TLS. It is strongly recommended that use of the following known broken
/// protocol versions be avoided:
/// - SSL v2
/// - SSL v3
/// - TLS v1
/// - TLS v1.1
/// Several highly publicized exploitable flaws have been discovered in all
/// versions of SSL and early versions of TLS. The following versions are
/// considered insecure, and should be avoided:
/// - SSL v2
/// - SSL v3
/// - TLS v1
/// - TLS v1.1
///
/// This method supports detection on the Python's built-in `ssl` module and
/// the `pyOpenSSL` module.
///
/// ## Example
/// ```python
Expand All @@ -39,81 +42,66 @@ pub struct SslInsecureVersion {
impl Violation for SslInsecureVersion {
#[derive_message_formats]
fn message(&self) -> String {
format!("Call made with insecure SSL protocol: {}", self.protocol)
let SslInsecureVersion { protocol } = self;
format!("Call made with insecure SSL protocol: `{protocol}`")
}
}

const INSECURE_SSL_PROTOCOLS: &[&str] = &[
"PROTOCOL_SSLv2",
"PROTOCOL_SSLv3",
"PROTOCOL_TLSv1",
"PROTOCOL_TLSv1_1",
"SSLv2_METHOD",
"SSLv23_METHOD",
"SSLv3_METHOD",
"TLSv1_METHOD",
"TLSv1_1_METHOD",
];

/// S502
pub(crate) fn ssl_insecure_version(checker: &mut Checker, call: &ExprCall) {
let keywords = match checker.semantic().resolve_call_path(call.func.as_ref()) {
Some(call_path) => match *call_path.as_slice() {
["ssl", "wrap_socket"] => vec!["ssl_version"],
["OpenSSL", "SSL", "Context"] => vec!["method"],
_ => vec!["ssl_version", "method"],
},
None => vec!["ssl_version", "method"],
let Some(keyword) = checker
.semantic()
.resolve_call_path(call.func.as_ref())
.and_then(|call_path| match call_path.as_slice() {
["ssl", "wrap_socket"] => Some("ssl_version"),
["OpenSSL", "SSL", "Context"] => Some("method"),
_ => None,
})
else {
return;
};

for arg in keywords {
let Some(keyword) = call.arguments.find_keyword(arg) else {
continue;
};
match &keyword.value {
Expr::Name(ast::ExprName { id, .. }) => {
let Some(val) = find_assigned_value(id, checker.semantic()) else {
continue;
};
match val {
Expr::Name(ast::ExprName { id, .. }) => {
if INSECURE_SSL_PROTOCOLS.contains(&id.as_str()) {
checker.diagnostics.push(Diagnostic::new(
SslInsecureVersion {
protocol: id.to_string(),
},
keyword.range,
));
}
}
Expr::Attribute(ast::ExprAttribute { attr, .. }) => {
if INSECURE_SSL_PROTOCOLS.contains(&attr.as_str()) {
checker.diagnostics.push(Diagnostic::new(
SslInsecureVersion {
protocol: attr.to_string(),
},
keyword.range,
));
}
}
_ => {
continue;
}
}
}
Expr::Attribute(ast::ExprAttribute { attr, .. }) => {
if INSECURE_SSL_PROTOCOLS.contains(&attr.as_str()) {
checker.diagnostics.push(Diagnostic::new(
SslInsecureVersion {
protocol: attr.to_string(),
},
keyword.range,
));
}
let Some(keyword) = call.arguments.find_keyword(keyword) else {
return;
};

match &keyword.value {
Expr::Name(ast::ExprName { id, .. }) => {
if is_insecure_protocol(&id) {
checker.diagnostics.push(Diagnostic::new(
SslInsecureVersion {
protocol: id.to_string(),
},
keyword.range(),
));
}
_ => {
continue;
}
Expr::Attribute(ast::ExprAttribute { attr, .. }) => {
if is_insecure_protocol(&attr) {
checker.diagnostics.push(Diagnostic::new(
SslInsecureVersion {
protocol: attr.to_string(),
},
keyword.range(),
));
}
}
_ => {}
}
}

/// Returns `true` if the given protocol name is insecure.
fn is_insecure_protocol(name: &str) -> bool {
matches!(
name,
"PROTOCOL_SSLv2"
| "PROTOCOL_SSLv3"
| "PROTOCOL_TLSv1"
| "PROTOCOL_TLSv1_1"
| "SSLv2_METHOD"
| "SSLv23_METHOD"
| "SSLv3_METHOD"
| "TLSv1_METHOD"
| "TLSv1_1_METHOD"
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S502.py:6:13: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv3
S502.py:6:13: S502 Call made with insecure SSL protocol: `PROTOCOL_SSLv3`
|
4 | from OpenSSL.SSL import Context
5 |
Expand All @@ -11,7 +11,7 @@ S502.py:6:13: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv3
8 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # S502
|

S502.py:7:17: S502 Call made with insecure SSL protocol: PROTOCOL_TLSv1
S502.py:7:17: S502 Call made with insecure SSL protocol: `PROTOCOL_TLSv1`
|
6 | wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) # S502
7 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # S502
Expand All @@ -20,7 +20,7 @@ S502.py:7:17: S502 Call made with insecure SSL protocol: PROTOCOL_TLSv1
9 | SSL.Context(method=SSL.SSLv2_METHOD) # S502
|

S502.py:8:17: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv2
S502.py:8:17: S502 Call made with insecure SSL protocol: `PROTOCOL_SSLv2`
|
6 | wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) # S502
7 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # S502
Expand All @@ -30,7 +30,7 @@ S502.py:8:17: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv2
10 | SSL.Context(method=SSL.SSLv23_METHOD) # S502
|

S502.py:9:13: S502 Call made with insecure SSL protocol: SSLv2_METHOD
S502.py:9:13: S502 Call made with insecure SSL protocol: `SSLv2_METHOD`
|
7 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # S502
8 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # S502
Expand All @@ -40,7 +40,7 @@ S502.py:9:13: S502 Call made with insecure SSL protocol: SSLv2_METHOD
11 | Context(method=SSL.SSLv3_METHOD) # S502
|

S502.py:10:13: S502 Call made with insecure SSL protocol: SSLv23_METHOD
S502.py:10:13: S502 Call made with insecure SSL protocol: `SSLv23_METHOD`
|
8 | ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # S502
9 | SSL.Context(method=SSL.SSLv2_METHOD) # S502
Expand All @@ -50,7 +50,7 @@ S502.py:10:13: S502 Call made with insecure SSL protocol: SSLv23_METHOD
12 | Context(method=SSL.TLSv1_METHOD) # S502
|

S502.py:11:9: S502 Call made with insecure SSL protocol: SSLv3_METHOD
S502.py:11:9: S502 Call made with insecure SSL protocol: `SSLv3_METHOD`
|
9 | SSL.Context(method=SSL.SSLv2_METHOD) # S502
10 | SSL.Context(method=SSL.SSLv23_METHOD) # S502
Expand All @@ -59,78 +59,14 @@ S502.py:11:9: S502 Call made with insecure SSL protocol: SSLv3_METHOD
12 | Context(method=SSL.TLSv1_METHOD) # S502
|

S502.py:12:9: S502 Call made with insecure SSL protocol: TLSv1_METHOD
S502.py:12:9: S502 Call made with insecure SSL protocol: `TLSv1_METHOD`
|
10 | SSL.Context(method=SSL.SSLv23_METHOD) # S502
11 | Context(method=SSL.SSLv3_METHOD) # S502
12 | Context(method=SSL.TLSv1_METHOD) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^ S502
|

S502.py:19:6: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv2
|
19 | func(ssl_version=ssl.PROTOCOL_SSLv2) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S502
20 | func(ssl_version=ssl.PROTOCOL_SSLv3) # S502
21 | func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
|

S502.py:20:6: S502 Call made with insecure SSL protocol: PROTOCOL_SSLv3
|
19 | func(ssl_version=ssl.PROTOCOL_SSLv2) # S502
20 | func(ssl_version=ssl.PROTOCOL_SSLv3) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S502
21 | func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
22 | func(method=SSL.SSLv2_METHOD) # S502
|

S502.py:21:6: S502 Call made with insecure SSL protocol: PROTOCOL_TLSv1
|
19 | func(ssl_version=ssl.PROTOCOL_SSLv2) # S502
20 | func(ssl_version=ssl.PROTOCOL_SSLv3) # S502
21 | func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S502
22 | func(method=SSL.SSLv2_METHOD) # S502
23 | func(method=SSL.SSLv23_METHOD) # S502
|

S502.py:22:6: S502 Call made with insecure SSL protocol: SSLv2_METHOD
|
20 | func(ssl_version=ssl.PROTOCOL_SSLv3) # S502
21 | func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
22 | func(method=SSL.SSLv2_METHOD) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^ S502
23 | func(method=SSL.SSLv23_METHOD) # S502
24 | func(method=SSL.SSLv3_METHOD) # S502
|

S502.py:23:6: S502 Call made with insecure SSL protocol: SSLv23_METHOD
|
21 | func(ssl_version=ssl.PROTOCOL_TLSv1) # S502
22 | func(method=SSL.SSLv2_METHOD) # S502
23 | func(method=SSL.SSLv23_METHOD) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^^ S502
24 | func(method=SSL.SSLv3_METHOD) # S502
25 | func(method=SSL.TLSv1_METHOD) # S502
|

S502.py:24:6: S502 Call made with insecure SSL protocol: SSLv3_METHOD
|
22 | func(method=SSL.SSLv2_METHOD) # S502
23 | func(method=SSL.SSLv23_METHOD) # S502
24 | func(method=SSL.SSLv3_METHOD) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^ S502
25 | func(method=SSL.TLSv1_METHOD) # S502
|

S502.py:25:6: S502 Call made with insecure SSL protocol: TLSv1_METHOD
|
23 | func(method=SSL.SSLv23_METHOD) # S502
24 | func(method=SSL.SSLv3_METHOD) # S502
25 | func(method=SSL.TLSv1_METHOD) # S502
| ^^^^^^^^^^^^^^^^^^^^^^^ S502
26 |
27 | wrap_socket(ssl_version=ssl.PROTOCOL_TLS_CLIENT) # OK
13 |
14 | wrap_socket(ssl_version=ssl.PROTOCOL_TLS_CLIENT) # OK
|


0 comments on commit 8f9e174

Please sign in to comment.