Step 2: Running Scan Commands Against a Server¶
Every type of scan that SSLyze can run against a server (supported cipher suites, session renegotiation, etc.) is represented by a ScanCommand.
Once a ScanCommand is run against a server, it returns a ScanResult which is an object with attributes containing the results of the scan. The list of attributes and what they mean depends on what kind of scan was run (ie. which ScanCommand).
All the available ScanCommands and corresponding ScanResults are described in Appendix: Available Scan Commands.
As explained in Step 1: Testing Connectivity to a Server, a properly initialized ServerConnectivityInfo is needed before the corresponding server can be scanned. Then, SSLyze can run ScanCommands against this server either:
- Sequentially using the SynchronousScanner class.
- Concurrently using the ConcurrentScanner class; this class is slightly more complex to use, but is also a lot faster when running a several ScanCommand and/or scanning multiple servers.
Running Commands Sequentially¶
Basic example¶
The SynchronousScanner class can be used to run ScanCommands against a server:
def demo_synchronous_scanner():
# Run one scan command to list the server's TLS 1.0 cipher suites
try:
server_tester = ServerConnectivityTester(
hostname='smtp.gmail.com',
port=587,
tls_wrapped_protocol=TlsWrappedProtocolEnum.STARTTLS_SMTP
)
print(f'\nTesting connectivity with {server_tester.hostname}:{server_tester.port}...')
server_info = server_tester.perform()
except ServerConnectivityError as e:
# Could not establish an SSL connection to the server
raise RuntimeError(f'Could not connect to {e.server_info.hostname}: {e.error_message}')
command = Tlsv10ScanCommand()
synchronous_scanner = SynchronousScanner()
scan_result = synchronous_scanner.run_scan_command(server_info, command)
for cipher in scan_result.accepted_cipher_list:
print(f' {cipher.name}')
The SynchronousScanner class¶
-
class
sslyze.synchronous_scanner.
SynchronousScanner
(network_retries=3, network_timeout=5)¶ An object to run SSL scanning commands synchronously against a server.
-
__init__
(network_retries=3, network_timeout=5)¶ Create a scanner for running scanning commands synchronously.
Parameters: - network_retries (
int
) – How many times SSLyze should retry a connection that timed out. - network_timeout (
int
) – The time until an ongoing connection times out.
Return type: None
- network_retries (
-
run_scan_command
(server_info, scan_command)¶ Run a single scan command against a server; will block until the scan command has been completed.
Parameters: - server_info (
ServerConnectivityInfo
) – The server’s connectivity information. The test_connectivity_to_server() method must have been called first to ensure that the server is online and accessible. - scan_command (
PluginScanCommand
) – The scan command to run against this server.
Return type: Returns: The result of the scan command, which will be an instance of the scan command’s corresponding PluginScanResult subclass.
- server_info (
-
Running Commands Concurrently¶
Basic example¶
The ConcurrentScanner uses a pool of processes to run ScanCommands concurrently. It is very fast when scanning a large number of servers, and it has a dispatching mechanism to avoid DOS-ing a single server against which multiple ScanCommand are run at the same time.
The commands can be queued using the queue_scan_command() method, and the results can later be retrieved using the get_results() method:
def demo_concurrent_scanner():
# Setup the server to scan and ensure it is online/reachable
server_info = demo_server_connectivity_tester()
# Run multiple scan commands concurrently. It is much faster than the SynchronousScanner
concurrent_scanner = ConcurrentScanner()
# Queue some scan commands
print('\nQueuing some commands...')
concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand())
concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())
# Process the results
print('\nProcessing results...')
for scan_result in concurrent_scanner.get_results():
# All scan results have the corresponding scan_command and server_info as an attribute
print(f'\nReceived result for "{scan_result.scan_command.get_title()}" '
f'on {scan_result.server_info.hostname}')
# A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult
if isinstance(scan_result, PluginRaisedExceptionScanResult):
raise RuntimeError(f'Scan command failed: {scan_result.scan_command.get_title()}')
# Each scan result has attributes with the information yo're looking for
# All these attributes are documented within each scan command's module
if isinstance(scan_result.scan_command, Tlsv12ScanCommand):
for cipher in scan_result.accepted_cipher_list:
print(f' {cipher.name}')
elif isinstance(scan_result.scan_command, CertificateInfoScanCommand):
# Print the Common Names within the verified certificate chain
if not scan_result.verified_certificate_chain:
print('Error: certificate chain is not trusted!')
else:
print('Certificate chain common names:')
for cert in scan_result.verified_certificate_chain:
cert_common_names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
print(f' {cert_common_names[0].value}')
The ConcurrentScanner class¶
-
class
sslyze.concurrent_scanner.
ConcurrentScanner
(network_retries=3, network_timeout=5, max_processes_nb=12, max_processes_per_hostname_nb=3)¶ An object to run SSL scanning commands concurrently by dispatching them using a pool of processes.
-
__init__
(network_retries=3, network_timeout=5, max_processes_nb=12, max_processes_per_hostname_nb=3)¶ Create a scanner for running scanning commands concurrently using a pool of processes.
Parameters: - network_retries (
int
) – How many times SSLyze should retry a connection that timed out. - network_timeout (
int
) – The time until an ongoing connection times out. - max_processes_nb (
int
) – The maximum number of processes to spawn for running scans concurrently. - max_processes_per_hostname_nb (
int
) – The maximum number of processes that can be used for running scans concurrently against a single server. A lower value will reduce the chances of DOS-ing the server.
Return type: None
- network_retries (
-
queue_scan_command
(server_info, scan_command)¶ Queue a scan command targeting a specific server.
Parameters: - server_info (
ServerConnectivityInfo
) – The server’s connectivity information. The test_connectivity_to_server() method must have been called first to ensure that the server is online and accessible. - scan_command (
PluginScanCommand
) – The scan command to run against this server.
Return type: None
- server_info (
-
get_results
()¶ Return the result of previously queued scan commands; new commands cannot be queued once this is called.
Return type: Iterable
[PluginScanResult
]Returns: The results of all the scan commands previously queued. Each result will be an instance of the scan corresponding command’s PluginScanResult subclass. If there was an unexpected error while running the scan command, it will be a ‘PluginRaisedExceptionScanResult’ instance instead.
-