swagger/scan/passive/
general.rs1use super::*;
2use std::collections::HashSet;
3
4pub trait PassiveGeneralScan {
5 fn check_server_url(&self) -> Vec<Alert>;
6 fn check_additional_properties(&self) -> Vec<Alert>;
7 fn check_successes(&self) -> Vec<Alert>;
8 fn check_default_response(&self) -> Vec<Alert>;
9 fn check_response_body_schema(&self) -> Vec<Alert>;
10 fn example_inconsistant_schema(&self) -> Vec<Alert>;
11 fn check_default_type(&self) -> Vec<Alert>;
12 fn check_enum_type(&self) -> Vec<Alert>;
13 fn check_required_undefined(&self) -> Vec<Alert>;
14 fn check_unused_schema(&self) -> Vec<Alert>;
15}
16
17impl<T: OAS + Serialize> PassiveGeneralScan for PassiveSwaggerScan<T> {
19 fn check_server_url(&self) -> Vec<Alert> {
21 let mut alerts = vec![];
22 let mut server_addrs = HashSet::new();
23 if let Some(servers) = &self.swagger.servers() {
24 alerts.extend(check_servers_for_server_url_rule(
25 servers,
26 "swagger root servers",
27 &mut server_addrs,
28 ));
29 }
30 for (path, item) in &self.swagger.get_paths() {
31 for (m, op) in item.get_ops() {
32 if let Some(servers) = &op.servers {
33 alerts.extend(check_servers_for_server_url_rule(
34 servers,
35 &format!("swagger {} {} servers", path, m),
36 &mut server_addrs,
37 ));
38 }
39 }
40 }
41 alerts
43 }
44 fn check_successes(&self) -> Vec<Alert> {
45 let mut alerts = vec![];
46 for (path, item) in &self.swagger.get_paths() {
47 for (m, op) in item.get_ops() {
48 let statuses = op
49 .responses()
50 .keys()
51 .cloned()
52 .collect::<Vec<String>>();
53 let mut found = false;
54 for status in statuses {
55 if let Ok(s) = status.parse::<u16>() {
56 if (200..300).contains(&s) {
57 found = true;
58 break;
59 }
60 }
61 }
62 if !found {
63 alerts.push(Alert::new(
64 Level::Low,
65 "Responses have no success status(2XX)",
66 format!("swagger path:{} operation:{}", path, m),
67 ));
68 }
69 }
70 }
71 alerts
72 }
73 fn check_additional_properties(&self) -> Vec<Alert> {
74 let mut alerts = vec![];
75 if let Some(comps) = &self.swagger.components() {
76 if let Some(schemas) = &comps.schemas {
77 for (name, schema) in schemas {
78 alerts.extend(additional_properties_test(
79 &schema.inner(&self.swagger_value),
80 format!("swagger root components schema:{}", name),
81 ))
82 }
83 }
84 }
85 alerts
86 }
87 fn check_default_response(&self) -> Vec<Alert> {
88 let mut alerts = vec![];
89 let message = "No default response defined";
90 for (responses, location) in get_responses(&self.swagger) {
91 if responses.get("default").is_none() {
92 alerts.push(Alert::new(Level::Low, message, location));
93 }
94 }
95 alerts
97 }
98 fn check_response_body_schema(&self) -> Vec<Alert> {
99 let mut alerts = vec![];
100 let message = "Response body doesn't have a schema";
101 for (responses, location) in get_responses(&self.swagger) {
102 for (status, response) in responses {
103 if let Some(content) = response.inner(&self.swagger_value).content {
104 for (name, m_t) in content {
105 if m_t.schema.is_none() {
106 alerts.push(Alert::new(
107 Level::Medium,
108 message,
109 format!("{} status:{} media type:{}", location, status, name),
110 ));
111 }
112 }
113 }
114 }
115 }
116 alerts
117 }
118 fn example_inconsistant_schema(&self) -> Vec<Alert> {
119 vec![]
120 }
121 fn check_default_type(&self) -> Vec<Alert> {
122 let mut alerts = vec![];
123 for (param, loc) in get_params(&self.swagger, &self.swagger_value) {
124 alerts.extend(param_default_rec(¶m, loc));
125 }
126 alerts
127 }
128 fn check_enum_type(&self) -> Vec<Alert> {
129 let mut alerts = vec![];
130 for (param, loc) in get_params(&self.swagger, &self.swagger_value) {
131 alerts.extend(param_enum_rec(¶m, loc));
132 }
133 alerts
134 }
135 fn check_required_undefined(&self) -> Vec<Alert> {
136 vec![]
137 }
138 fn check_unused_schema(&self) -> Vec<Alert> {
139 let mut alerts = vec![];
140 let swagger_str = serde_json::to_string(&self.swagger).unwrap();
141 if let Some(comps) = &self.swagger.components() {
142 if let Some(schemas) = &comps.schemas {
143 for name in schemas.keys() {
144 let schema_path = format!("#/components/schemas/{}", name);
145 if !swagger_str.contains(&schema_path) {
146 alerts.push(Alert::new(
147 Level::Info,
148 "Schema is defined but never used",
149 format!("swagger root components schema:{}", name),
150 ));
151 }
152 }
153 }
154 }
155 alerts
156 }
157}