We want to monitor a web site that is requesting SSL Client certificates. Is this possible?
Can PRTG monitor https sites that are protected with SSL client certificates
Votes:
0
Best 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.
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.
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.
Votes:
0
It's unfortunately not possible to send a cookie with a web request in PRTG at this time.
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]
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
Add comment