Step 2: Running Scan Commands Against a Server¶
Every type of scan that SSLyze can run against a server (supported cipher suites, Heartbleed, etc.) is
represented by a ScanCommand
. Once a ScanCommand
is run against a server, it returns a “result” object with
attributes containing the results of the scan command.
All the available ScanCommands
and corresponding results are described in Appendix: Scan Commands.
Basic Example¶
The main class for running these commands is the Scanner
class, which uses a pool of workers to run
ScanCommand
concurrently. It is very fast when scanning a large number of servers, and it has a rate-limiting
mechanism to avoid DOS-ing a single server against which multiple ScanCommand
are run at the same time.
The commands can be queued by passing a ServerScanRequest
to the Scanner.queue_scan()
method.
The results can later be retrieved using the Scanner.get_results()
method, which returns an iterable of
ServerScanResult
. Each result is returned as soon as the server scan was completed.
A simple example on how to run some scan commands follows:
def basic_example() -> None:
# Define the server that you want to scan
server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("www.google.com", 443)
# Do connectivity testing to ensure SSLyze is able to connect
try:
server_info = ServerConnectivityTester().perform(server_location)
except ConnectionToServerFailed as e:
# Could not connect to the server; abort
print(f"Error connecting to {server_location}: {e.error_message}")
return
# Then queue some scan commands for the server
scanner = Scanner()
server_scan_req = ServerScanRequest(
server_info=server_info, scan_commands={ScanCommand.CERTIFICATE_INFO, ScanCommand.SSL_2_0_CIPHER_SUITES},
)
scanner.queue_scan(server_scan_req)
# Then retrieve the results
for server_scan_result in scanner.get_results():
print(f"\nResults for {server_scan_result.server_info.server_location.hostname}:")
# SSL 2.0 results
ssl2_result = server_scan_result.scan_commands_results[ScanCommand.SSL_2_0_CIPHER_SUITES]
print("\nAccepted cipher suites for SSL 2.0:")
for accepted_cipher_suite in ssl2_result.accepted_cipher_suites:
print(f"* {accepted_cipher_suite.cipher_suite.name}")
# Certificate info results
certinfo_result = server_scan_result.scan_commands_results[ScanCommand.CERTIFICATE_INFO]
print("\nCertificate info:")
for cert_deployment in certinfo_result.certificate_deployments:
print(f"Leaf certificate: \n{cert_deployment.received_certificate_chain_as_pem[0]}")
Advanced Usage¶
The following script provides an example of running scan commands against multiple servers, and processing the results:
def main() -> None:
# First validate that we can connect to the servers we want to scan
servers_to_scan = []
for hostname in ["cloudflare.com", "google.com"]:
server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup(hostname, 443)
try:
server_info = ServerConnectivityTester().perform(server_location)
servers_to_scan.append(server_info)
except ConnectionToServerFailed as e:
print(f"Error connecting to {server_location.hostname}:{server_location.port}: {e.error_message}")
return
scanner = Scanner()
# Then queue some scan commands for each server
for server_info in servers_to_scan:
server_scan_req = ServerScanRequest(
server_info=server_info, scan_commands={ScanCommand.CERTIFICATE_INFO, ScanCommand.SSL_2_0_CIPHER_SUITES},
)
scanner.queue_scan(server_scan_req)
# Then retrieve the result of the scan commands for each server
for server_scan_result in scanner.get_results():
print(f"\nResults for {server_scan_result.server_info.server_location.hostname}:")
# Scan commands that were run with no errors
try:
ssl2_result = server_scan_result.scan_commands_results[ScanCommand.SSL_2_0_CIPHER_SUITES]
print("\nAccepted cipher suites for SSL 2.0:")
for accepted_cipher_suite in ssl2_result.accepted_cipher_suites:
print(f"* {accepted_cipher_suite.cipher_suite.name}")
except KeyError:
pass
try:
certinfo_result = server_scan_result.scan_commands_results[ScanCommand.CERTIFICATE_INFO]
print("\nCertificate info:")
for cert_deployment in certinfo_result.certificate_deployments:
print(f"Leaf certificate: \n{cert_deployment.received_certificate_chain_as_pem[0]}")
except KeyError:
pass
# Scan commands that were run with errors
for scan_command, error in server_scan_result.scan_commands_errors.items():
print(f"\nError when running {scan_command}:\n{error.exception_trace}")
Related Classes¶
-
class
sslyze.
Scanner
(per_server_concurrent_connections_limit=None, concurrent_server_scans_limit=None)¶ The main class to use in order to call and schedule SSLyze’s scan commands from Python.
- Parameters
per_server_concurrent_connections_limit (
Optional
[int
]) –concurrent_server_scans_limit (
Optional
[int
]) –
-
queue_scan
(server_scan)¶ Queue a server scan.
- Parameters
server_scan (
ServerScanRequest
) –- Return type
None
-
get_results
()¶ Return completed server scans.
- Return type
Iterable
[ServerScanResult
]
-
class
sslyze.
ServerScanRequest
(server_info, scan_commands, scan_commands_extra_arguments=<factory>)¶ A request to scan a specific server with the supplied scan commands.
- Parameters
server_info (
ServerConnectivityInfo
) –scan_commands (
Set
[Literal
[‘certificate_info’, ‘ssl_2_0_cipher_suites’, ‘ssl_3_0_cipher_suites’, ‘tls_1_0_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_2_cipher_suites’, ‘tls_1_3_cipher_suites’, ‘tls_compression’, ‘tls_1_3_early_data’, ‘openssl_ccs_injection’, ‘tls_fallback_scsv’, ‘heartbleed’, ‘robot’, ‘session_renegotiation’, ‘session_resumption’, ‘session_resumption_rate’, ‘http_headers’, ‘elliptic_curves’]]) –scan_commands_extra_arguments (
ScanCommandExtraArgumentsDict
) –
-
class
sslyze.
ServerScanResult
(scan_commands_results, scan_commands_errors, server_info, scan_commands, scan_commands_extra_arguments)¶ The result of a ServerScanRequest that was completed by a Scanner.
- Parameters
scan_commands_results (
ScanCommandResultsDict
) –scan_commands_errors (
Dict
[Literal
[‘certificate_info’, ‘ssl_2_0_cipher_suites’, ‘ssl_3_0_cipher_suites’, ‘tls_1_0_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_2_cipher_suites’, ‘tls_1_3_cipher_suites’, ‘tls_compression’, ‘tls_1_3_early_data’, ‘openssl_ccs_injection’, ‘tls_fallback_scsv’, ‘heartbleed’, ‘robot’, ‘session_renegotiation’, ‘session_resumption’, ‘session_resumption_rate’, ‘http_headers’, ‘elliptic_curves’],ScanCommandError
]) –server_info (
ServerConnectivityInfo
) –scan_commands (
Set
[Literal
[‘certificate_info’, ‘ssl_2_0_cipher_suites’, ‘ssl_3_0_cipher_suites’, ‘tls_1_0_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_1_cipher_suites’, ‘tls_1_2_cipher_suites’, ‘tls_1_3_cipher_suites’, ‘tls_compression’, ‘tls_1_3_early_data’, ‘openssl_ccs_injection’, ‘tls_fallback_scsv’, ‘heartbleed’, ‘robot’, ‘session_renegotiation’, ‘session_resumption’, ‘session_resumption_rate’, ‘http_headers’, ‘elliptic_curves’]]) –scan_commands_extra_arguments (
ScanCommandExtraArgumentsDict
) –
-
class
sslyze.
ScanCommandResultsDict
(**kwargs)¶ A dictionary of results for every scan command that was scheduled against a specific server.
-
certificate_info
: sslyze.plugins.certificate_info.implementation.CertificateInfoScanResult¶
-
ssl_2_0_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
ssl_3_0_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
tls_1_0_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
tls_1_1_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
tls_1_2_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
tls_1_3_cipher_suites
: sslyze.plugins.openssl_cipher_suites.implementation.CipherSuitesScanResult¶
-
tls_compression
: sslyze.plugins.compression_plugin.CompressionScanResult¶
-
tls_1_3_early_data
: sslyze.plugins.early_data_plugin.EarlyDataScanResult¶
-
openssl_ccs_injection
: sslyze.plugins.openssl_ccs_injection_plugin.OpenSslCcsInjectionScanResult¶
-
tls_fallback_scsv
: sslyze.plugins.fallback_scsv_plugin.FallbackScsvScanResult¶
-
heartbleed
: sslyze.plugins.heartbleed_plugin.HeartbleedScanResult¶
-
robot
: sslyze.plugins.robot.implementation.RobotScanResult¶
-
session_renegotiation
: sslyze.plugins.session_renegotiation_plugin.SessionRenegotiationScanResult¶
-
session_resumption
: sslyze.plugins.session_resumption.implementation.SessionResumptionSupportScanResult¶
-
session_resumption_rate
: sslyze.plugins.session_resumption.implementation.SessionResumptionRateScanResult¶
-
http_headers
: sslyze.plugins.http_headers_plugin.HttpHeadersScanResult¶
-
elliptic_curves
: sslyze.plugins.elliptic_curves_plugin.SupportedEllipticCurvesScanResult¶
-
-
sslyze.
ScanCommandErrorsDict
¶
Exporting to JSON¶
A ServerScanResult
can be serialized to JSON using SSLyze’s special JsonEncoder
.
-
class
sslyze.
JsonEncoder
(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)¶ Special JSON encoder that can serialize any ServerScanResult returned by SSLyze.
A ServerScanResult can be serialized to JSON using the following code:
>>> from dataclasses import asdict >>> import json >>> import sslyze >>> >>> scanner = sslyze.Scanner() >>> # Queue some ServerScanRequest... and then retrieve the results... >>> for server_scan_result in scanner.get_results(): >>> server_scan_result_as_json = json.dumps(asdict(server_scan_result), cls=sslyze.JsonEncoder)