-
Notifications
You must be signed in to change notification settings - Fork 883
/
ssh_no_host_key_verification.rs
92 lines (83 loc) · 2.72 KB
/
ssh_no_host_key_verification.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{Expr, ExprAttribute, ExprCall};
use ruff_python_semantic::analyze::typing;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for uses of policies disabling SSH verification in Paramiko.
///
/// ## Why is this bad?
/// By default, Paramiko checks the identity of remote host when establishing
/// an SSH connection. Disabling the verification might lead to the client
/// connecting to a malicious host, without the client knowing.
///
/// ## Example
/// ```python
/// from paramiko import client
///
/// ssh_client = client.SSHClient()
/// ssh_client.set_missing_host_key_policy(client.AutoAddPolicy)
/// ```
///
/// Use instead:
/// ```python
/// from paramiko import client
///
/// ssh_client = client.SSHClient()
/// ssh_client.set_missing_host_key_policy()
/// ```
///
/// ## References
/// - [Paramiko documentation: set_missing_host_key_policy](https://docs.paramiko.org/en/latest/api/client.html#paramiko.client.SSHClient.set_missing_host_key_policy)
#[violation]
pub struct SSHNoHostKeyVerification;
impl Violation for SSHNoHostKeyVerification {
#[derive_message_formats]
fn message(&self) -> String {
format!("Paramiko call with policy set to automatically trust the unknown host key")
}
}
fn extract_policy_argument(call: &ExprCall) -> Option<&Expr> {
return match call.arguments.find_argument("policy", 0) {
Some(Expr::Call(ExprCall { func, .. })) => Some(func.as_ref()),
Some(argument) => Some(argument),
_ => None,
};
}
/// S507
pub(crate) fn ssh_no_host_key_verification(checker: &mut Checker, call: &ExprCall) {
let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else {
return;
};
if attr.as_str() != "set_missing_host_key_policy" {
return;
}
let Some(policy_argument) = extract_policy_argument(call) else {
return;
};
if !checker
.semantic()
.resolve_call_path(policy_argument)
.is_some_and(|call_path| {
matches!(
call_path.as_slice(),
["paramiko", "client", "AutoAddPolicy" | "WarningPolicy"]
| ["paramiko", "AutoAddPolicy" | "WarningPolicy"]
)
})
{
return;
}
if typing::resolve_assignment(value, checker.semantic()).is_some_and(|call_path| {
matches!(
call_path.as_slice(),
["paramiko", "client", "SSHClient"] | ["paramiko", "SSHClient"]
)
}) {
checker.diagnostics.push(Diagnostic::new(
SSHNoHostKeyVerification,
policy_argument.range(),
));
}
}