title: Invoke-RestMethod with anti-forgery tokens in header and cookie
date: 2017-02-21 14:14:00 +0200 +0200
draft: false
author: John Roos
----
To help prevent cross-site scripting attacks some websites uses anti-forgery tokens. If you would like to talk to a REST API which uses this security measure you might run into problems if you are trying to use the PowerShell cmdlet Invoke-RestMethod. I have seen some people suggesting that Invoke-RestMethod does not have support for this, which is not true. It’s just a little bit more complicated than expected.
What’s needed is basically a custom header and a cookie. It’s the last part with the cookie which makes people think that Invoke-RestMethod does not work because it does not support cookies. It does. The header goes into the header parameter as expected, but the cookie need to go into a web session variable which is used for the websession parameter.
So let’s get into the code. First we need the basics, like uri, content type and all that.
[System.Uri]$Uri = "http://pizzaserver.example.com/api/pizza/1"
$ContentType = "application/json"
$Method = 'PUT'
$Body = '{ "id" = 1, "Name" = "Peperoni" }'
So now we have a small body which we are going to use to update a record in the REST API using the PUT method. Now the cookie. It’s a very simple .Net class which is kind of like a small hash table. Change the name and value into what is needed for your anti-forgery token.
$Cookie = New-Object System.Net.Cookie
$Cookie.Name = "My cookie name"
$Cookie.Value = "My cookie value"
$Cookie.Domain = $uri.DnsSafeHost
Create the web session and add the cookie to it.
$WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession
$WebSession.Cookies.Add($Cookie)
That’s actually everything you need for the cookie. Next is the header. Modify the name and value to match the other token.
$Headers = @{
'My header name' = 'My header value'
}
Now we are ready to run Invoke-RestMethod. I prefer to use splatting for the parameters.
$props = @{
Uri = $uri.AbsoluteUri
Headers = $Headers
ContentType = $ContentType
Method = $Method
WebSession = $WebSession
Body = $Body
}
Invoke-RestMethod @props That’s it. Now we can talk to a secure REST API.
Full script
[System.Uri]$Uri = "http://pizzaserver.example.com/api/pizza/1"
$ContentType = "application/json"
$Method = 'PUT'
$Body = '{ "id" = 1, "Name" = "Peperoni" }'
$Cookie = New-Object System.Net.Cookie
$Cookie.Name = "My cookie name"
$Cookie.Value = "My cookie value"
$Cookie.Domain = $uri.DnsSafeHost
$WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$WebSession.Cookies.Add($Cookie)
$Headers = @{
'My header name' = 'My header value'
}
$props = @{
Uri = $uri.AbsoluteUri
Headers = $Headers
ContentType = $ContentType
Method = $Method
WebSession = $WebSession
Body = $Body
}
Invoke-RestMethod @props
Invoke-RestMethod with anti-forgery tokens in header and cookie
To help prevent cross-site scripting attacks some websites uses anti-forgery tokens. If you would like to talk to a REST API which uses this security measure you might run into problems if you are trying to use the PowerShell cmdlet Invoke-RestMethod. I have seen some people suggesting that Invoke-RestMethod does not have support for this, which is not true. It’s just a little bit more complicated than expected.
What’s needed is basically a custom header and a cookie. It’s the last part with the cookie which makes people think that Invoke-RestMethod does not work because it does not support cookies. It does. The header goes into the header parameter as expected, but the cookie need to go into a web session variable which is used for the websession parameter.
So let’s get into the code. First we need the basics, like uri, content type and all that.
[System.Uri]$Uri = "http://pizzaserver.example.com/api/pizza/1"
$ContentType = "application/json"
$Method = 'PUT'
$Body = '{ "id" = 1, "Name" = "Peperoni" }'
So now we have a small body which we are going to use to update a record in the REST API using the PUT method. Now the cookie. It’s a very simple .Net class which is kind of like a small hash table. Change the name and value into what is needed for your anti-forgery token.
$Cookie = New-Object System.Net.Cookie
$Cookie.Name = "My cookie name"
$Cookie.Value = "My cookie value"
$Cookie.Domain = $uri.DnsSafeHost
Create the web session and add the cookie to it.
$WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession
$WebSession.Cookies.Add($Cookie)
That’s actually everything you need for the cookie. Next is the header. Modify the name and value to match the other token.
$Headers = @{
'My header name' = 'My header value'
}
Now we are ready to run Invoke-RestMethod. I prefer to use splatting for the parameters.
$props = @{
Uri = $uri.AbsoluteUri
Headers = $Headers
ContentType = $ContentType
Method = $Method
WebSession = $WebSession
Body = $Body
}
Invoke-RestMethod @props That’s it. Now we can talk to a secure REST API.
Full script
[System.Uri]$Uri = "http://pizzaserver.example.com/api/pizza/1"
$ContentType = "application/json"
$Method = 'PUT'
$Body = '{ "id" = 1, "Name" = "Peperoni" }'
$Cookie = New-Object System.Net.Cookie
$Cookie.Name = "My cookie name"
$Cookie.Value = "My cookie value"
$Cookie.Domain = $uri.DnsSafeHost
$WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$WebSession.Cookies.Add($Cookie)
$Headers = @{
'My header name' = 'My header value'
}
$props = @{
Uri = $uri.AbsoluteUri
Headers = $Headers
ContentType = $ContentType
Method = $Method
WebSession = $WebSession
Body = $Body
}
Invoke-RestMethod @props
- Written by John Roos on February 21, 2017