Daniel Beck, could you please explain how the code here (the example you linked above) is not compatible with SECURITY-1491? I read SECURITY-1491 very carefully and stepped through the code in the Java debugger, and as far as I can tell I am doing everything correctly in Swarm:
- First, hudson.plugins.swarm.SwarmClient#createSwarmSlave creates an instance of HttpClientContext.
- Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb calls the crumbIssuer API, successfully obtaining a crumb request field and a crumb. The server's response sets a JSESSIONID cookie, which is visible in the HttpClientContext's BasicCookieStore (e.g., JSESSIONID.472fe218).
- Next, hudson.plugins.swarm.SwarmClient#createSwarmSlave adds the CSRF header returned by hudson.plugins.swarm.SwarmClient#getCsrfCrumb to the POST request.
- Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb executes the POST request. During this process, org.apache.http.client.protocol.RequestAddCookies examines the HttpClientContext's BasicCookieStore, finds the JSESSIONID cookie, and adds it to the set of headers before making the HTTP POST request.
The key invariants for all this to work are that the HTTP GET in SwarmClient#getCsrfCrumb must always be called immediately before making any POST request, the HttpClientContext (and therefore the BasicCookieStore) must always be shared between the CSRF crumb retrieval GET and the subsequent POST, and the POST must contain both a CSRF header (obtained from the previous CSRF crumb retrieval GET) and a JSESSIONID header (which must be the same JSESSIONID from the previous CSRF crumb retrieval GET). As far as I can tell, I am meeting all of these invariants in my code. Furthermore, as I explained in JENKINS-59193, I cannot reproduce any CSRF-related issue, either in integration tests or against my production Jenkins instance running 2.204.4 with DefaultCrumbIssuer enabled. If there is something I am doing wrong, I would like to know what it is and/or how I could reproduce any potential issues. |