CSRF Protection

Cross-Site Request Forgery Protection

A malicious page open in an administrator's browser could post to http://jenkins.example.com/job/deploy/build, and the browser would attach the session cookie. Jenkins 8,793 therefore demands a crumb with every state-changing POST: a token from /crumbIssuer, tied to the web session that fetched it. Since Jenkins 2.222 the UI has no switch to turn this off, and requests authenticated with an API token are exempt, because no browser sends one on its own:

Starting a build with a password, an API token and a crumbGroovy
PASS=$(cat ~/v5-ch5/.secrets/jenkins-admin); B=$J/job/sec-hello/build
code() { curl -s -o /dev/null -w '%{http_code}\n' "$@"; }
echo "password, no crumb:  $(code -u "admin:$PASS" -X POST $B)"
echo "API token, no crumb: $(code -u "admin:$JENKINS_TOKEN" -X POST $B)"
CRUMB=$(curl -s -c jar -u "admin:$PASS" $J/crumbIssuer/api/json | jq -r .crumb)
echo "crumb, no session:   $(code -u "admin:$PASS" -H "Jenkins-Crumb: $CRUMB" -X POST $B)"
echo "crumb + session:     $(code -b jar -u "admin:$PASS" -H "Jenkins-Crumb: $CRUMB" -X POST $B)"
Output
password, no crumb:  403
API token, no crumb: 201
crumb, no session:   403
crumb + session:     201

The first 403 page says "No valid crumb was included in the request". Scripts should authenticate with API tokens, as this chapter's do; a script that insists on a password must keep the cookie jar with its crumb.