swagger/scan/passive/
general.rs

1use 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
17///Rule fucntions implementation
18impl<T: OAS + Serialize> PassiveGeneralScan for PassiveSwaggerScan<T> {
19    ///Can raise no https alert and invalid url in server alert
20    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        //println!("{:?}",alerts);
42        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        //println!("{:?}",alerts);
96        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(&param, 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(&param, 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}