What is this?

This knowledgebase contains questions and answers about PRTG Network Monitor and network monitoring in general.

Learn more

PRTG Network Monitor

Intuitive to Use. Easy to manage.
More than 500,000 users rely on Paessler PRTG every day. Find out how you can reduce cost, increase QoS and ease planning, as well.

Free Download

Top Tags


View all Tags

Can PRTG monitor https sites that are protected with SSL client certificates

Votes:

0

We want to monitor a web site that is requesting SSL Client certificates. Is this possible?

client-certificates https monitor prtg ssl

Created on Jan 29, 2015 3:05:25 PM



Best Answer

Accepted Answer

Votes:

8

Here is the final script I'am using with correct exit codes for the custom sensors: (https://www.paessler.com/manuals/prtg7/api_for_custom_exe_sensors)

$TypeDefinition_ClientCertWebClient = @"
public class ClientCertWebClient : System.Net.WebClient
{
    System.Net.HttpWebRequest request = null;
    System.Security.Cryptography.X509Certificates.X509CertificateCollection certificates = null;

    protected override System.Net.WebRequest GetWebRequest(System.Uri address)
    {
        request = (System.Net.HttpWebRequest)base.GetWebRequest(address);
        if (certificates != null)
        {
            request.ClientCertificates.AddRange(certificates);
        }
        return request;
    }

    public void AddCerts(System.Security.Cryptography.X509Certificates.X509Certificate[] certs)
    {
        if (certificates == null)
        {
            certificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
        }
        if (request != null)
        {
            request.ClientCertificates.AddRange(certs);
        }
        certificates.AddRange(certs);
   }
}
"@

Try
{
    Add-Type -TypeDefinition $TypeDefinition_ClientCertWebClient
}
Catch
{
}

Function Test-Portal
{
    $WebClient = New-Object -TypeName ClientCertWebClient
    $Certificate = Get-ChildItem -Path Cert:\LocalMachine\My\447FA04BC24F469XXXXXXXX234F7D54501
    $WebClient.AddCerts($Certificate)
    $WebClient.Headers.Add("Cookie","DM-Identity=prtg.uptime.monitor@invalid")
    Try
    {
        $WebClient.DownloadString("https://xxxxx.xxxxxxxx.xx")
    }
    Catch
    {
        if ($_.Exception.ErrorRecord.Exception.Message.Contains("The remote server returned an error: (401) Unauthorized."))
        {
            write-host "1:UP"
            exit 0
        }
    }
    write-host "0:DOWN"
    exit 2
}
Test-Portal

Created on Feb 6, 2015 1:46:35 PM

Last change on Feb 6, 2015 2:01:51 PM by  Torsten Lindner [Paessler Support]



8 Replies

Votes:

0

What are you looking to monitor on the site? If the site has an API where you can pull XML values from then you should be able to monitor quite a bit but it really depends on how the site is set up and what you want to monitor.

Created on Jan 30, 2015 12:04:56 PM by  Greg Campion [Paessler Support]



Votes:

0

I want to monitor the uptime of a site. For security in front of the web server there is a reverse proxy. A Client SSL Certificate is used authenticate to the proxy. Checks the attributes of the certificate and Sets a cookie. Before it forces a reload of the site. When the site reloads with the cookie the proxy passes the request to the web server. The website returns a 401 error to the PRTG server. This is a valid response for the monitor because the response is coming from the web server. So the web server must be up and running. For legal reasons we do not want real access to the website.

It is possible to insert an invalid cookie in the request to bypass the reload of the site. This will make the web server respond with 401. But the client certificate is needed for all connections to the site.

Created on Jan 30, 2015 4:33:03 PM



Votes:

0

If your question is if a sensor in PRTG can provide client certificates to web sites, you can at least do so with a custom sensor: the PowerShell cmdlet Invoke-WebRequests supports client certificates using the -Certificate option. The return value in an object representing the requested web site (HtmlWebResponseObject), which makes paring easier as with plain text.

Created on Feb 2, 2015 2:43:41 PM



Votes:

0

It's unfortunately not possible to send a cookie with a web request in PRTG at this time.

Created on Feb 2, 2015 4:07:12 PM by  Greg Campion [Paessler Support]



Votes:

7

Thanks Ages,

I have a powershell script which can handle client certificates and cookies. At this moment it Returns True or False. I have to change this to something the custom sensor can handle. I will look in to this tomorrow.

The current script:

$TypeDefinition_ClientCertWebClient = @"
public class ClientCertWebClient : System.Net.WebClient
{
    System.Net.HttpWebRequest request = null;
    System.Security.Cryptography.X509Certificates.X509CertificateCollection certificates = null;

    protected override System.Net.WebRequest GetWebRequest(System.Uri address)
    {
        request = (System.Net.HttpWebRequest)base.GetWebRequest(address);
        if (certificates != null)
        {
            request.ClientCertificates.AddRange(certificates);
        }
        return request;
    }

    public void AddCerts(System.Security.Cryptography.X509Certificates.X509Certificate[] certs)
    {
        if (certificates == null)
        {
            certificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
        }
        if (request != null)
        {
            request.ClientCertificates.AddRange(certs);
        }
        certificates.AddRange(certs);
   }
}
"@

Try
{
    Add-Type -TypeDefinition $TypeDefinition_ClientCertWebClient
}
Catch
{
}

Function Test-Portal
{
    $WebClient = New-Object -TypeName ClientCertWebClient
    $Certificate = Get-ChildItem -Path Cert:\CurrentUser\My\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    $WebClient.AddCerts($Certificate)
    Try
    {
        $WebClient.DownloadString("https://XXXXXX.XXXXXX.XX")
    }

    Catch
    {
        if ($_.Exception.ErrorRecord.Exception.Message.Contains("Too many automatic redirections were attempted."))
        {
            $WebClient.Headers.Add("Cookie","XXXXXXXXX=YYYYYYYYYYYYYYYYYY")
            Try
            {
                $WebClient.DownloadString("https://XXXXXX.XXXXXX.XX")
            }

            Catch
            {
                return ($_.Exception.ErrorRecord.Exception.Message.Contains("The remote server returned an error: (401) Unauthorized."))
            }
        }
        else
        {
            return $false
        }
    }
}

(Measure-Command -Expression {$TestResult = Test-Portal}).TotalMilliseconds
$TestResult

Created on Feb 2, 2015 5:33:47 PM

Last change on Feb 3, 2015 9:37:46 AM by  Torsten Lindner [Paessler Support]



Accepted Answer

Votes:

8

Here is the final script I'am using with correct exit codes for the custom sensors: (https://www.paessler.com/manuals/prtg7/api_for_custom_exe_sensors)

$TypeDefinition_ClientCertWebClient = @"
public class ClientCertWebClient : System.Net.WebClient
{
    System.Net.HttpWebRequest request = null;
    System.Security.Cryptography.X509Certificates.X509CertificateCollection certificates = null;

    protected override System.Net.WebRequest GetWebRequest(System.Uri address)
    {
        request = (System.Net.HttpWebRequest)base.GetWebRequest(address);
        if (certificates != null)
        {
            request.ClientCertificates.AddRange(certificates);
        }
        return request;
    }

    public void AddCerts(System.Security.Cryptography.X509Certificates.X509Certificate[] certs)
    {
        if (certificates == null)
        {
            certificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
        }
        if (request != null)
        {
            request.ClientCertificates.AddRange(certs);
        }
        certificates.AddRange(certs);
   }
}
"@

Try
{
    Add-Type -TypeDefinition $TypeDefinition_ClientCertWebClient
}
Catch
{
}

Function Test-Portal
{
    $WebClient = New-Object -TypeName ClientCertWebClient
    $Certificate = Get-ChildItem -Path Cert:\LocalMachine\My\447FA04BC24F469XXXXXXXX234F7D54501
    $WebClient.AddCerts($Certificate)
    $WebClient.Headers.Add("Cookie","DM-Identity=prtg.uptime.monitor@invalid")
    Try
    {
        $WebClient.DownloadString("https://xxxxx.xxxxxxxx.xx")
    }
    Catch
    {
        if ($_.Exception.ErrorRecord.Exception.Message.Contains("The remote server returned an error: (401) Unauthorized."))
        {
            write-host "1:UP"
            exit 0
        }
    }
    write-host "0:DOWN"
    exit 2
}
Test-Portal

Created on Feb 6, 2015 1:46:35 PM

Last change on Feb 6, 2015 2:01:51 PM by  Torsten Lindner [Paessler Support]



Votes:

0

other variant of script, based on original solution:

  • powershell-only solution (no dependency on .NET assembly. On PRTG you do not need to tweak original solution to run, because of restricted security context)
  • tests that your proxy denies anonymous users. Because you need also to know if your proxy is not misconfigured. (Because providing the certificate to certificate-not-backed-up web renders the web fine. But the sensor should not consider this situation OK)
param (
	[string]$targetUrl = "N/A"
)
# monitor https sites that are protected with SSL client certificates
# source https://kb.paessler.com/en/topic/63094-can-prtg-monitor-https-sites-that-are-protected-with-ssl-client-certificates



$transcript 	  = $false
$debug            = $false 
# thumb gotten in context of username@MACHINENAME with Get-ChildItem -Path "Cert:CurrentUser\My"
# parent device of PRTG sensor must be configured to run under the same Windows username@MACHINENAME account, in order to see the certificate
$certificateThumb = "!!!insertYOURS!!!"  # example AB85A43423CFD6BCBCDD5BDA1616C02881E1EAA5
$userAgent        = "PRTG powershell custom script" 

################ end of settings
Set-Variable -name userAgent -value $userAgent -scope global 
Set-Variable -name returnStatusDescription -value "" -scope global
$Error.Clear()

if ($transcript) { Start-Transcript -path "c:\tmp\http-content-monitor-with-SSL-client-cert--VERSION2.ps1.log" }

if ($targetUrl -eq "N/A") {
	$targetUrl = "https://example.org"
	write-Host "Skript expect the only parameter (URL), it was not supplied, so setting it to $targetUrl"
}




function Test-withoutCertificate($targetUrl)
{
	try {
		$a 		    = wget $targetUrl -TimeoutSec 30 -useBasicParsing -userAgent $global:userAgent 
		$statusCode = $a.statusCode
		$statusDesc = $a.statusDescription
	} catch {
		$statusCode = $_.Exception.Response.StatusCode.value__
		$statusDesc = $_.Exception.Response.StatusDescription
	}
	 $global:returnStatusDescription += "noCert=$statusCode $statusDesc; "
	if ($debug) {
		write-host -noNewLine "noCert=$statusCode $statusDesc; "
		write-host $error[0]
		#write-host $a
	}
	
	$exptectedStatus = @(400, 403)
	if ($exptectedStatus -contains $statusCode) {
		return 0
	}	
	$global:returnStatusDescription += "Code $statusCode is responseStatus for request WITHOUT certificate. Expected one of the responseStatuses $exptectedStatus. //"  
	return 1
}

function Test-WithCertificate($url, $thumbprint)
{	
	try {
		$a 		    = wget $targetUrl -TimeoutSec 30 -useBasicParsing -userAgent $global:userAgent -certificateThumbprint $thumbprint 
		$statusCode = $a.statusCode
		$statusDesc = $a.statusDescription
	} catch {
		$statusCode = $_.Exception.Response.StatusCode.value__
		$statusDesc = $_.Exception.Response.StatusDescription
	}
	$global:returnStatusDescription += "withCert=$statusCode $statusDesc; "
	if ($debug) {
		write-host -noNewLine "withCert=$statusCode $statusDesc; "
		write-host $error[0]
		#write-host $a
	}
	$exptectedStatus = @(200, 401)
	if ($exptectedStatus -contains $statusCode) {
		return 0
	}
	$global:returnStatusDescription += "Code $statusCode is responseStatus for request WITH certificate. Expected one of the responseStatuses $exptectedStatus. //"  

	return 1
}


[int] $test1 = Test-withCertificate    $targetUrl $certificateThumb
[int] $test2 = Test-withoutCertificate $targetUrl 

if ($transcript) { Stop-Transcript }

if (($test1 + $test2) -eq 0) {
	# character ":" is reserved separator character between PRTG status code (0-ok,1-warning,3-neterr apod) and its description
	write-host "0:OK ($returnStatusDescription)"
	exit 0
} else {
	$global:returnStatusDescription += "Additional errormsg is '" + ($error[0] -replace "`r|`n"," " ) + "'"
	write-host "1:Warning ($returnStatusDescription)"
	exit 1
}



Created on Apr 16, 2021 1:30:45 PM

Last change on Apr 16, 2021 2:45:07 PM by  Felix Wiesneth [Paessler Support]



Votes:

0

Hi Petr,

Thank you for sharing!


Kind regards

Felix Wiesneth - Team Tech Support

Created on Apr 16, 2021 2:13:07 PM by  Felix Wiesneth [Paessler Support]




Disclaimer: The information in the Paessler Knowledge Base comes without warranty of any kind. Use at your own risk. Before applying any instructions please exercise proper system administrator housekeeping. You must make sure that a proper backup of all your data is available.