CSRF Protection Explained

Environment


Issue

How do I enable CSRF protection?

Resolution

GOTO: Jenkins > Manage Jenkins > Configure Global Security and enable Prevent Cross Site Request Forgery exploits.

Select Default Crumb Issuer from Crumb Algorithm and save to apply changes and enable.

See the CSRF Protection Wiki page for more.


Issue

Do I need a CSRF crumb?

Resolution

If you authenticate your API calls with a username and password, a valid crumb is required. Starting from Jenkins LTS 2.176.2 a valid Web Session for which the crumb was issued is also required unless configured otherwise.

If you authenticate your API calls with a username and a user API token then a crumb is not required from Jenkins 2.96 weekly / 2.107 LTS. For more information please refer to CSRF crumb no longer required when authenticating using API token or JENKINS-22474.

Note that the API Token system was improved in Jenkins LTS 2.138.1


Issue

How do I generate a crumb?

Resolution

Using wget

wget --user=admin --password=admin --auth-no-challenge -q --output-document - 'http://localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'

The output is the crumb.

Parameters:

  • --user=<USERNAME>
  • --password=<PASSWORD_OR_API_TOKEN>

Replace http://localhost:8080 with your Jenkins URL.

Using cURL

curl -u "admin:admin" 'http://localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'

The output is the crumb.

Parameters:

  • -u "<USERNAME>:<PASSWORD_OR_API_TOKEN>"

Replace http://localhost:8080 with your Jenkins URL.

Debugging Issues

I’m seeing the following response:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 404 Not Found</title>
</head>
<body><h2>HTTP ERROR 404</h2>
<p>Problem accessing /crumbIssuer/api/xml. Reason:
<pre>    Not Found</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>
...
...

CSRF Protection is not enabled. GOTO: Jenkins > Manage Jenkins > Configure Global Security and enable Prevent Cross Site Request Forgery exploits.


Issue

How do I use an issued crumb in an API call.

Resolution

Using wget

The following example retrieves a crumb and uses it to build a job called someJob.

Before 2.176.2, no session required:

# Replace with your Jenkins URL and admin credentials
SERVER="http://localhost:8080"
CRUMB=$(wget --user=admin --password=admin --auth-no-challenge -q --output-document - "$SERVER"/crumbIssuer/api/xml?xpath=concat\(//crumbRequestField,%22:%22,//crumb\))
wget --user=admin --password=admin --auth-no-challenge --header="$CRUMB" --post-data="" -q "$SERVER"/job/someJob/build

After 2.176.2, session is required:

# Replace with your Jenkins URL and admin credentials
SERVER="http://localhost:8080"
# File where web session cookie is saved 
COOKIEJAR="$(mktemp)"
CRUMB="$(wget --user=admin --password=admin --auth-no-challenge --save-cookies "$COOKIEJAR" --keep-session-cookies -q --output-document - "$SERVER/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)")"
wget --user=admin --password=admin --auth-no-challenge --load-cookies "$COOKIEJAR" --header="$CRUMB" --post-data="" -q "$SERVER"/job/someJob/build

Parameters:

  • --user=<USERNAME>
  • --password=<PASSWORD_OR_API_TOKEN>
  • --header="<ISSUED_CRUMB_FOR_USER>"

Using cURL

The following example retrieves a crumb and uses it to build a job called someJob.

Before 2.176.2, no session required:

# Replace with your Jenkins URL and admin credentials
SERVER="http://localhost:8080"
CRUMB=$(curl -u "admin:admin" "$SERVER"/crumbIssuer/api/xml?xpath=concat\(//crumbRequestField,%22:%22,//crumb\))
curl -X POST -u "admin:admin" -H "$CRUMB" "$SERVER"/job/someJob/build

After 2.176.2, session is required:

# Replace with your Jenkins URL and admin credentials
SERVER="http://localhost:8080"
# File where web session cookie is saved
COOKIEJAR="$(mktemp)"
CRUMB=$(curl -u "admin:admin" --cookie-jar "$COOKIEJAR" "$SERVER/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)")
curl -X POST -u "admin:admin" --cookie "$COOKIEJAR" -H "$CRUMB" "$SERVER"/job/someJob/build

Parameters:

  • -u "<USERNAME>:<PASSWORD_OR_API_TOKEN>"
  • -H "<ISSUED_CRUMB_FOR_USER>"

Debugging Issues

I’m seeing the following response:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 403 No valid crumb was included in the request</title>
</head>
<body><h2>HTTP ERROR 403</h2>
<p>Problem accessing /job/someJob/build. Reason:
<pre>    No valid crumb was included in the request</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>
...
...

This is caused by an invalid crumb being used.


Issue

Does the crumb expire?

Resolution

Once an user has received a crumb, it can be re-used for all subsequent requests as long as this user stays in the same session. At code level, this dependency can be seen here.

Note :

  1. Session may expire on its own depending on Jenkins settings.
  2. Session might be aborted due to unexpected reasons, such as Failover of HA in CJP or SSO expiration
  3. So generally keeping the same crumb is safe for short command sequences, but not for scripts running for several hours

Issue

How is the crumb generated?

Resolution

Using MD5. The crumb is a combination of user authentication (if authentication is applied), originating IP address and the crumb salt.


Issue

Is the crumb salt configurable?

Resolution

Currently no. It is hard-coded.

Have more questions?

1 Comments

  • 0
    Avatar
    Mark Kenneally

    Is this page up to date?  Shouldn't the crumbRequestField be Jenkins-Crumb: not .crumb: ?

Please sign in to leave a comment.