Skip to content

Commit

Permalink
Added HSTS checks
Browse files Browse the repository at this point in the history
* check-ssl-hsts-preload.rb - for checking the preload status of a domain
* check-ssl-hsts-preloadable.rb - for checking if a domain can be preloaded
  • Loading branch information
rwky authored and majormoses committed Sep 26, 2017
1 parent eab1575 commit fc68b08
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
## [Unreleased]
### Added
- Ruby 2.4.1 testing
- `check-ssl-hsts-preload.rb`: Added check for testing preload status of HSTS
- `check-ssl-hsts-preloadable.rb`: Added check for testing if a domain can be HSTS preloaded

## [1.4.0] - 2017-06-20
### Added
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* bin/check-ssl-crl.rb
* bin/check-ssl-cert.rb
* bin/check-ssl-host.rb
* bin/check-ssl-hsts-preload.rb
* bin/check-ssl-hsts-preloadable.rb
* bin/check-ssl-qualys.rb

## Usage
Expand Down
79 changes: 79 additions & 0 deletions bin/check-ssl-hsts-preloadable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env ruby
# encoding: UTF-8
# check-ssl-hsts-preloadable.rb
#
# DESCRIPTION:
# Checks a domain against the chromium HSTS API returning errors/warnings if the domain is preloadable
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
#
# USAGE:
# # Basic usage
# check-ssl-hsts-preloadable.rb -d <domain_name>
#
# LICENSE:
# Copyright 2017 Rowan Wookey <[email protected]>
# Released under the same terms as Sensu (the MIT license); see LICENSE for
# details.
#
# Inspired by https://github.com/sensu-plugins/sensu-plugins-ssl/blob/master/bin/check-ssl-qualys.rb Copyright 2015 William Cooke <[email protected]>
#

require 'sensu-plugin/check/cli'
require 'json'
require 'net/http'

class CheckSSLHSTSPreloadable < Sensu::Plugin::Check::CLI
option :domain,
description: 'The domain to run the test against',
short: '-d DOMAIN',
long: '--domain DOMAIN',
required: true

option :api_url,
description: 'The URL of the API to run against',
long: '--api-url URL',
default: 'https://hstspreload.org/api/v2/preloadable'

def fetch(uri, limit = 10)
if limit == 0
return nil
end

response = Net::HTTP.get_response(uri)

case response
when Net::HTTPSuccess then
response
when Net::HTTPRedirection then
location = URI(response['location'])
fetch(location, limit - 1)
end
end

def run
uri = URI(config[:api_url])
uri.query = URI.encode_www_form(domain: config[:domain])
response = fetch(uri)
if response.nil?
return warning 'Bad response recieved from API'
end
body = JSON.parse(response.body)
if !body['errors'].empty?
critical body['errors'].map { |u| u['summary'] }.join(', ')
elsif !body['warnings'].empty?
warning body['warnings'].map { |u| u['summary'] }.join(', ')
else
ok
end
end
end

# vim: set tabstop=2 shiftwidth=2 expandtab:
101 changes: 101 additions & 0 deletions bin/check-ssl-hsts-status.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env ruby
# encoding: UTF-8
# check-ssl-hsts-preload.rb
#
# DESCRIPTION:
# Checks a domain against the chromium HSTS API reporting on the preload status of the domain
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
#
# USAGE:
# # Basic usage
# check-ssl-hsts-preload.rb -d <domain_name>
# # Specify the CRITICAL and WARNING alerts to either unknown (not in the database), pending or preloaded
# check-ssl-hsts-preload.rb -d <domain_name> -c <critical_alert> -w <warning_alert>
#
# LICENSE:
# Copyright 2017 Rowan Wookey <[email protected]>
# Released under the same terms as Sensu (the MIT license); see LICENSE for
# details.
#
# Inspired by https://github.com/sensu-plugins/sensu-plugins-ssl/blob/master/bin/check-ssl-qualys.rb Copyright 2015 William Cooke <[email protected]>
#

require 'sensu-plugin/check/cli'
require 'json'
require 'net/http'

class CheckSSLHSTSStatus < Sensu::Plugin::Check::CLI
STATUSES = %w(unknown pending preloaded).freeze

option :domain,
description: 'The domain to run the test against',
short: '-d DOMAIN',
long: '--domain DOMAIN',
required: true

option :warn,
short: '-w STATUS',
long: '--warn STATUS',
description: 'WARNING if this status or worse',
in: STATUSES,
default: 'pending'

option :critical,
short: '-c STATUS',
long: '--critical STATUS',
description: 'CRITICAL if this status or worse',
in: STATUSES,
default: 'unknown'

option :api_url,
description: 'The URL of the API to run against',
long: '--api-url URL',
default: 'https://hstspreload.org/api/v2/status'

def fetch(uri, limit = 10)
if limit == 0
return nil
end

response = Net::HTTP.get_response(uri)

case response
when Net::HTTPSuccess then
response
when Net::HTTPRedirection then
location = URI(response['location'])
fetch(location, limit - 1)
end
end

def run
uri = URI(config[:api_url])
uri.query = URI.encode_www_form(domain: config[:domain])
response = fetch(uri)
if response.nil?
return warning 'Bad response recieved from API'
end
body = JSON.parse(response.body)
unless STATUSES.include? body['status']
warning 'Invalid status returned ' + body['status']
end

if STATUSES.index(body['status']) <= STATUSES.index(config[:critical])
critical body['status']
elsif STATUSES.index(body['status']) <= STATUSES.index(config[:warn])
warning body['status']
else
ok
end
end
end

# vim: set tabstop=2 shiftwidth=2 expandtab:
33 changes: 33 additions & 0 deletions test/check-ssl-hsts-preloadable_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require_relative '../bin/check-ssl-hsts-preloadable.rb'
###
# If these randomly start failing then it's probably due to a change in the HSTS of the domain
# feel free to raise an issue and mention @rwky on github for a fix
###

describe CheckSSLHSTSPreloadable do
before(:all) do
# Ensure the check isn't run when exiting (which is the default)
CheckSSLHSTSPreloadable.class_variable_set(:@@autorun, nil)
end

let(:check) do
CheckSSLHSTSPreloadable.new ['-d', 'hstspreload.org']
end

it 'should pass check if the domain is preloadedable and has no warnings' do
expect(check).to receive(:ok).and_raise SystemExit
expect { check.run }.to raise_error SystemExit
end

it 'should pass check if the domain is preloadedable but has warnings' do
check.config[:domain] = 'garron.net'
expect(check).to receive(:warning).and_raise SystemExit
expect { check.run }.to raise_error SystemExit
end

it 'should pass check if not preloadedable' do
check.config[:domain] = 'example.com'
expect(check).to receive(:critical).and_raise SystemExit
expect { check.run }.to raise_error SystemExit
end
end
27 changes: 27 additions & 0 deletions test/check-ssl-hsts-status_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require_relative '../bin/check-ssl-hsts-status.rb'
###
# If these randomly start failing then it's probably due to a change in the HSTS of the domain
# feel free to raise an issue and mention @rwky on github for a fix
###

describe CheckSSLHSTSStatus do
before(:all) do
# Ensure the check isn't run when exiting (which is the default)
CheckSSLHSTSStatus.class_variable_set(:@@autorun, nil)
end

let(:check) do
CheckSSLHSTSStatus.new ['-d', 'hstspreload.org']
end

it 'should pass check if the domain is preloaded' do
expect(check).to receive(:ok).and_raise SystemExit
expect { check.run }.to raise_error SystemExit
end

it 'should pass check if not preloaded' do
check.config[:domain] = 'example.com'
expect(check).to receive(:critical).and_raise SystemExit
expect { check.run }.to raise_error SystemExit
end
end

0 comments on commit fc68b08

Please sign in to comment.