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

No comments

Post a Comment