How to show TLS handshake information and CONNECT request in Invoke-WebRequest - powershell

When I'm accessing a site through HTTPS and/or with HTTP proxy, cURL in Linux provides the -v/--verbose flag to show the CONNECT request to the proxy, as well as the SSL/TLS handshake process (including certificate), like
* Rebuilt URL to: https://www.example.com/
* Trying 192.168.2.1...
* Connected to my-proxy.local (192.168.2.1) port 8080 (#0)
* Establish HTTP proxy tunnel to www.example.com:443
> CONNECT www.example.com:443 HTTP/1.1
> Host: www.example.com:443
> User-Agent: curl/7.47.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection established
<
* Proxy replied OK to CONNECT request
* found 148 certificates in /etc/ssl/certs/ca-certificates.crt
* found 597 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: www.example.org (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #3
* subject: C=US,ST=California,L=Los Angeles,O=Internet Corporation for Assigned Names and Numbers,OU=Technology,CN=www.example.org
* start date: Tue, 03 Nov 2015 00:00:00 GMT
* expire date: Wed, 28 Nov 2018 12:00:00 GMT
* issuer: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert SHA2 High Assurance Server CA
* compression: NULL
* ALPN, server accepted to use http/1.1
> GET / HTTP/1.1
> Host: www.example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Cache-Control: max-age=604800
< Content-Type: text/html
< Date: Mon, 27 Nov 2017 23:08:55 GMT
< Etag: "359670651+gzip+ident"
< Expires: Mon, 04 Dec 2017 23:08:55 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: ECS (ord/4C84)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1270
<
< (body...)
Is there anyway to get similar information when using Invoke-WebRequest? Or should I use another CmdLet? I tried -Debug and -Verbose, both of which shows neither information. Even the raw content only contains the actual request after proxy, that is, in the above example the GET / HTTP/1.1.
In brief, I want to see something like the line
> CONNECT www.example.com:443 HTTP/1.1
and
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256

You can get some of this information from the .RawContent property of Invoke-WebRequest. Unfortunately if you opt for Invoke-RestMethod, PowerShell basically discards all of the HTTP information which you're interested.
For this example, I'll use https://jsonplaceholder.typicode.com/posts, which is a good test REST Endpoint for fiddling with things like this.
First, I'll make a connection to the site and store it in a Variable, $response.
$response = Invoke-WebRequest -uri https://jsonplaceholder.typicode.com/posts
Now I can interrogate and pull out some of the useful fields to get some of the info you're looking for.
$response.BaseResponse
IsMutuallyAuthenticated : False
Cookies : {__cfduid=d84018de2d621df9d53eb52d97cd33a651511881763}
Headers : {Transfer-Encoding, Connection, Vary, Access-Control-Allow-Credentials...}
SupportsHeaders : True
ContentLength : -1
ContentEncoding :
ContentType : application/json; charset=utf-8
CharacterSet : utf-8
Server : cloudflare-nginx
LastModified : 11/28/2017 10:17:27 AM
StatusCode : OK
StatusDescription : OK
ProtocolVersion : 1.1
ResponseUri : https://jsonplaceholder.typicode.com/posts
Method : GET
IsFromCache : False
We can also get some good info in the first 25 lines or so of the RawContent property, as seen here. RawContent is, well, raw, so I apply a split on new-lines then use array indexing as depicted by [0..20] to select the first 21 lines.
$response.RawContent.Split("`n")[0..20]
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Origin, Accept-Encoding
Access-Control-Allow-Credentials: true
Pragma: no-cache
X-Content-Type-Options: nosniff
CF-Cache-Status: HIT
CF-RAY: 3c4e3f804f9d82f7-ATL
Cache-Control: public, max-age=14400
Content-Type: application/json; charset=utf-8
Date: Tue, 28 Nov 2017 15:09:23 GMT
Expires: Tue, 28 Nov 2017 19:09:23 GMT
ETag: W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM"
Set-Cookie: __cfduid=d84018de2d621df9d53eb52d97cd33a651511881763; expires=Wed, 28-Nov-18 15:09:23 GMT; path=/; domain=.typicode.com; HttpOnly
Server: cloudflare-nginx
Via: 1.1 vegur
X-Powered-By: Express
I agree that it would be nice to be able to get this information back too. I'll open up an issue on the github.com/PowerShell repo and see if we can get something like this added in the future, and the link will be added to this answer.

Related

Add Access-Control header to Google Domain 301 redirect

I'm trying to add the following header to my 301 redirect from https://id.danielbakas.com to https://pod.danielbakas.com:
Access-Control-Allow-Origin: *
My 301 redirect was setup using Google Domain's "Website Redirect", but I can't seem to find any documentation about adding headers to the redirect.
If you were to curl the origin URL you would find that the Access-Control-Allow-Origin header is missing:
curl --head https://id.danielbakas.com
HTTP/2 301
location: https://pod.danielbakas.com/profile/card
date: Wed, 14 Dec 2022 17:36:39 GMT
content-type: text/html; charset=UTF-8
server: ghs
content-length: 237
x-xss-protection: 0
x-frame-options: SAMEORIGIN
However, if you were to curl the destination URL, you would find that the header is indeed present:
curl --head https://pod.danielbakas.com/profile/card
HTTP/1.1 200 OK
Vary: Accept,Authorization,Origin
X-Powered-By: Community Solid Server
Updates-Via: wss://pod.danielbakas.com/
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Accept-Patch,Accept-Post,Accept-Put,Allow,ETag,Last-Modified,Link,Location,Updates-Via,WAC-Allow
Allow: OPTIONS, HEAD, GET, PATCH, PUT, DELETE
Accept-Patch: text/n3, application/sparql-update
Accept-Put: */*
Content-Type: text/turtle
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <https://pod.danielbakas.com/profile/card.meta>; rel="describedby"
Link: <https://pod.danielbakas.com/profile/card.acl>; rel="acl"
Last-Modified: Mon, 12 Dec 2022 20:21:11 GMT
ETag: "1670876471000"
WAC-Allow: user="read",public="read"
Date: Wed, 14 Dec 2022 17:38:07 GMT
Connection: keep-alive
Keep-Alive: timeout=5
How could I configure this redirect so that this header is present in the origin URL?
Thank you so much!

How to get 103 Early Hints work in Traefik?

I am using traefik in kubernetes and I have a service deployed that is returning 103 Early Hint. I can confirm that it is working by directly querying the service, e.g.
curl -D - http://contra-web-app
HTTP/1.1 103 Early Hints
Link: <https://builds.contra.com>; rel="preconnect"; crossorigin
Link: <https://fonts.googleapis.com/css2?family=Inter:wght#400;500;600;700;900&display=swap>; rel="preload"; as="font"
Link: <https://builds.contra.com/3f509d0cc/assets/entry-client-routing.4f895d55.js>; rel="modulepreload"; as="script"; crossorigin
Link: <https://www.googletagmanager.com/gtag/js?id=G-96H5NXQ2PR>; rel="preload"; as="script"
HTTP/1.1 200 OK
cache-control: no-store
referrer-policy: strict-origin-when-cross-origin
x-frame-options: sameorigin
content-type: text/html
content-length: 9062
Date: Tue, 26 Jul 2022 20:34:19 GMT
Connection: keep-alive
Keep-Alive: timeout=72
However, requesting the same service through Traefik just returns 200 response:
curl -H 'host: contra.com' -D - http://contra-traefik.traefik/gajus
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Length: 11441
Content-Type: text/html
Date: Tue, 26 Jul 2022 19:51:48 GMT
Referrer-Policy: strict-origin-when-cross-origin
Set-Cookie: contra_web_app_service=394e7e912ad85b66; Path=/; Secure
Vary: Accept-Encoding
X-Frame-Options: sameorigi
At this point, I am unable to establish whether I am missing a configuration or if Traefik does not support it.

Getting a 401 status error whilst establishing a connection to Concourse API

At the moment, we are trying to get CI working in our labs..
we have just followed the instructions on the concourse website.
We are able to login properly and have setup ~/.flyrc as recomended ion the concourse-ci.org and concoursetutorial.com websites.
We have noticed that most commands are returning with a 401 Unauthorized error.
We have gone ahead setup the audit logs https://concourse-ci.org/concourse-web.html#audit-logs
But it isn't clear where this writes to, help?
It is difficult at the moment to properly trace this. BTW this is our first exposure to concourse.
We would like to know why? and what we can do resolve this (to cross this huddle).
fly -t rdb-ci set-team --team-name a-team --local-user admin --github-org organization --verbose --print-table-headers --non-interactive
2019/07/10 22:02:37 GET /api/v1/info HTTP/1.1
Host: ci.example.org
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
2019/07/10 22:02:37 HTTP/1.1 200 OK
Content-Length: 88
Connection: keep-alive
Content-Type: application/json
Date: Wed, 10 Jul 2019 21:02:37 GMT
Server: nginx/1.12.2
X-Concourse-Version: 5.3.0
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: deny
X-Xss-Protection: 1; mode=block
{"version":"5.3.0","worker_version":"2.1","external_url":"https://ci.example.org"}
setting team: a-team
role owner:
users:
- local:admin
groups:
- github:organization
apply team configuration? [yN]: y
2019/07/10 22:02:53 PUT /api/v1/teams/a-team HTTP/1.1
Host: ci.example.org
User-Agent: Go-http-client/1.1
Content-Length: 71
Content-Type: application/json
Accept-Encoding: gzip
{"auth":{"owner":{"groups":["github:organization"],"users":["local:admin"]}}}
2019/07/10 22:02:53 HTTP/1.1 401 Unauthorized
Content-Length: 14
Connection: keep-alive
Content-Type: text/plain; charset=utf-8
Date: Wed, 10 Jul 2019 21:02:53 GMT
Server: nginx/1.12.2
X-Concourse-Version: 5.3.0
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: deny
X-Xss-Protection: 1; mode=block
not authorized
could not find a valid token.
logging in to team 'main'
2019/07/10 22:02:53 GET /api/v1/info HTTP/1.1
Host: ci.example.org
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
could not reach the Concourse server called rdb-ci:
Get https://ci.example.org/api/v1/info: x509: certificate is valid for www.example.org, not ci.example.org
is the targeted Concourse running? better go catch it lol

UnparseableJsonResponse: API Version 1

My first app for Google Home has just been released, but it's in the "unhealthy" status.
Looking at the logs, I see that the response received is :
Received response from agent with body: HTTP/1.1 200 OK
Date: Thu, 01 Mar 2018 16:36:44 GMT
Content-Type: application/json
Content-Length: 174
Connection: keep-alive
Cache-Control: private, must-revalidate
Google-Actions-API-Version: 2
expires: -1
Vary: Accept-Encoding
Content-Encoding: gzip
Accept-Ranges: bytes
X-Cache: MISS
{"expectUserResponse":false,"finalResponse":{"richResponse":{"items":[{"simpleResponse":{"ssml":"<speak>This is AppBundle\\ActionsOnGoogle\\DictionaryEndpoint</speak>","displayText":"This is AppBundle\\ActionsOnGoogle\\DictionaryEndpoint"}}]}}}.
and yet I have "UnparseableJsonResponse: API Version 1: Failed to parse JSON response string with error"
I can't understand what's wrong with health probe :
My Google Home work fine (conversations are okay)
It works fine in the simulator too
API version in response is "2" not "1"
JSon response is valide
Anyone can help ?
Thanks
Frederic

Get content-length from a URL which redirects to itself

I want to get content-length from a URL that it sends me this header:
HTTP/1.1 301 Moved Permanently Date: Sun, 01 Jan 2012 09:34:44 GMT Server: Apache Location: https://www.sugarsync.com, www.sugarsync.com/pf/D6304231_0192919_76577 Keep-Alive: timeout=300, max=9793 Connection: Keep-Alive Content-Type: text/plain; charset=UTF-8
The problem is that the original URL is the same new URL that in this header is sent! In other words: I get the headers from URL: https://www.sugarsync.com/pf/D6304231_0192919_76577 and in headers that I get, it redirects to the same page.
I don't seem to have that problem with the URL you provided:
C:\Users\rleahy>openssl s_client -quiet -connect sugarsync.com:443
Loading 'screen' into random state - done
depth=1 /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates
.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=
07969287
verify error:num=20:unable to get local issuer certificate
verify return:0
HEAD /pf/D6304231_0192919_76577 HTTP/1.1
host:www.sugarsync.com
HTTP/1.1 200 OK
Date: Sun, 01 Jan 2012 10:16:13 GMT
Server: Apache
Set-Cookie: JSESSIONID=22C35505626E63560F5F00BDE86BD458; Path=/; Secure
Content-Disposition: attachment;filename="Algorithms(01).rar"
Accept-Ranges: bytes
Etag: file_1319015834000
Last-Modified: Wed, 19 Oct 2011 09:17:14 GMT
Content-Length: 468987
Content-Type: application/x-download
Set-Cookie: NSC_wt_xxx.tvhbstzod.dpn_443=ffffffff090d78d545525d5f4f58455e445a4a4
2378b;path=/;secure;httponly
Are you sure you're not connecting with HTTP rather than HTTPS? Connecting with HTTP does indeed give a 301 (asking you -- in effect -- to connect using HTTPS).