Basic CSRF protection middleware for Ambiorix
When a request comes in (it ignores GET, HEAD, and OPTIONS)
it checks for the presence of a token.
It looks for said token in the following places, in that order:
_csrf in the body of the response
(e.g.: what was POSTed, see form example below),
both JSON and multipart.query for _csrf value (?_csrf=token)csrf-token
xsrf-token
x-csrf-token
x-xsrf-token
Where you need this token it can be retrieved with
req$csrf_token.
# install.packages("remotes")
# remotes::install_github("ambiorix-web/surf")
install.packages("surf", repos = c('https://ambiorix-web.r-universe.dev', 'https://cloud.r-project.org'))
Valid
library(surf)
library(ambiorix)
app <- Ambiorix$new()
# use the middleware
app$use(surf())
app$get("/", \(req, res){
res$sendf(
"<h1>What's your name?</h1>
<form action='/' method='POST' enctype='multipart/form-data'>
<input type='hidden' name='_csrf' value='%s' />
<input type='text' name='name' />
<input type='submit' value='send'/>
</form>",
req$csrf_token() # get token
)
})
app$post("/", \(req, res) {
body <- req$parse_multipart()
res$sendf("Hi %s", body$name)
})
app$start()
Invalid
library(surf)
library(ambiorix)
app <- Ambiorix$new()
# use the middleware
app$use(surf())
app$get("/", \(req, res){
# missing CSRF token
res$send(
"<h1>What's your name?</h1>
<form action='/' method='POST' enctype='multipart/form-data'>
<input type='text' name='name' />
<input type='submit' value='send'/>
</form>"
)
})
app$post("/", \(req, res) {
body <- req$parse_multipart()
res$sendf("Hi %s", body$name)
})
app$start()