记录Jenkins新版本API请求出现403的Crumb问题

问题描述

近期将jenkins从低版本升级到最新的2.312版本之后,对jenkins发起的API调用,均出现 403 错误。

curl -s -XPOST http://127.0.0.1:8080/credentials/store/system/domain/_/createCredentials \
> --user admin:pass@word1 --data-urlencode 'json={
quote>   "": "0",
quote>   "credentials": {
quote>     "scope": "GLOBAL",
quote>     "id": "credential_id_here",
quote>     "username": "username_here",
quote>     "password": "password_here",
quote>     "description": "My new credentials",
quote>     "$class": "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
quote>   }
quote> }'
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 403 No valid crumb was included in the request</title>
</head>
<body><h2>HTTP ERROR 403 No valid crumb was included in the request</h2>
<table>
<tr><th>URI:</th><td>/credentials/store/system/domain/_/createCredentials</td></tr>
<tr><th>STATUS:</th><td>403</td></tr>
<tr><th>MESSAGE:</th><td>No valid crumb was included in the request</td></tr>
<tr><th>SERVLET:</th><td>Stapler</td></tr>
</table>
<hr><a href="https://eclipse.org/jetty">Powered by Jetty:// 9.4.43.v20210629</a><hr/>

</body>
</html>

根据网上查找的资料显示,是由于jenkins开启了 CSRF Protection , 其实低版本也有这个功能,只是可能不完善,或者没有限制的这么死,如下图所示:

image-20210918143631334

上图中左侧为升级前的旧版本 2.183,右侧为新版本 2.312,可以看到旧版本允许关闭跨域保护,新版本不允许。经过一轮测试和研究,发现确实无法关闭。

仔细阅读jenkins文档,发现CSRF有以下说明:

https://www.jenkins.io/doc/bo...

The Default Crumb Issuer encodes the following information in the hash used as crumb:

  • The user name that the crumb was generated for
  • The web session ID that the crumb was generated in
  • The IP address of the user that the crumb was generated for
  • A salt) unique to this Jenkins instance

All of this information needs to match when a crumb is sent back to Jenkins for that submission to be considered valid.

The only supported option Enable proxy compatibility removes information about the user IP address from the token. This can be useful when Jenkins is running behind a reverse proxy and a user’s IP address as seen from Jenkins would regularly change.

大概意思是说,默认启用的The *Default Crumb Issuer, 这个拦截器会计算传递的crumb值的hash是否是可用hash, 这个hash的来源是通过用户名、sessionID,请求IP,以及访问的jenkins的唯一标识生成的。

其中唯一可以用的配置项 Enable proxy compatibility, 只开放IP的校验,这可以使用在使用网络代理的场景中。

如何解决

根据这份文档,看起来对jenkins的调用,必须要先请求一个crumb的hash值,在每次请求的时候传递给它,例如:

JENKINS_CRUMB=$(curl -s 'http://127.0.0.1:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' --user admin:pass@word1)

curl -s -XPOST  -H "Jenkins-Crumb:8dbf1060a4fd7a0120da0dd1a678cf82149dcd45d868c7799b760e79132fb774" http://127.0.0.1:8080/credentials/store/system/domain/_/createCredentials \
--user admin:pass@word1 --data-urlencode 'json={
  "": "0",
  "credentials": {
    "scope": "GLOBAL",
    "id": "credential_id_here",
    "username": "username_here",
    "password": "password_here",
    "description": "My new credentials",
    "$class": "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
  }
}'

根据上面这个网上找到的案例,发现运行之后还是会产生403,其中JENKINS_CRUMB确定是有值的,见鬼了。

文档欠缺的时候就是这样无语,耗费了时间查找网上可能的案例时,终于发现一个更多的信息:

image-20210918144548737

看起来还需要多传递一个cokkie的信息,不管有没有用,先测试再说,没想到真的成功了,jenkins官方为什么不给一个例子呢,吐槽....

有效测试如下:

curl -verbose  -s 'http://127.0.0.1:8080/crumbIssuer/api/json' --user admin:pass@word1
* About to connect() to 127.0.0.1 port 8080 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'admin'
> GET /crumbIssuer/api/json HTTP/1.1
> Authorization: Basic YWRtaW46cGFzc0B3b3JkMQ==
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8080
> Accept: */*
> Referer: rbose
>
< HTTP/1.1 200 OK
< Date: Sat, 18 Sep 2021 06:48:15 GMT
< X-Content-Type-Options: nosniff
< X-Jenkins: 2.312
< X-Jenkins-Session: 4af5e654
< X-Frame-Options: deny
< Content-Type: application/json;charset=utf-8
< Set-Cookie: JSESSIONID.443fa9b8=node08lm1pknhy9zr1nr1gd79rdpd725.node0; Path=/; HttpOnly # 注意JSESSIONID
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Content-Length: 163
< Server: Jetty(9.4.43.v20210629)
<
* Connection #0 to host 127.0.0.1 left intact
{"_class":"hudson.security.csrf.DefaultCrumbIssuer","crumb":"7f0ad0185a3a25c101ef654af337de01b822f2c4220a819ce1daaae7c61da059","crumbRequestField":"Jenkins-Crumb"}#

~ curl -s -XPOST --cookie "JSESSIONID.443fa9b8=node08lm1pknhy9zr1nr1gd79rdpd725.node0" -H "Jenkins-Crumb:7f0ad0185a3a25c101ef654af337de01b822f2c4220a819ce1daaae7c61da059" \
http://127.0.0.1:8080/credentials/store/system/domain/_/createCredentials \
--user admin:pass@word1 --data-urlencode 'json={
  "": "0",
  "credentials": {
    "scope": "GLOBAL",
    "id": "credential_id_here",
    "username": "测试crumb",
    "password": "password_here",
    "description": "My new credentials",
    "$class": "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
  }
}'

如上例子所示,需要再传递的时候增加cokkie和header,传递JSESSIONID和Jenkins-Crumb,以及账号密码或者token.那么程序发起调用之前,还需要先请求session和crumb,并保持session,如果session过期,还会出现403, 其中少不了容错处理的部分。


4 声望
1 粉丝
0 条评论
推荐阅读
QUIC 学习入门概念及资料整理
在学习QUIC协议的路上,有很多的博客把QUIC的协议讲的很透彻,但是对于一些入门的细节并没有讲的很清楚,导致在学习QUIC的时候,存在一定的困难。在这篇文章里,我将补充一些有利于新手理解QUIC协议的知识点。

行愚阅读 339

使用Jenkins优雅部署Java项目【超级详细的实战教程】
环境准备centos 7Java 1.8Maven 3.6.3Docker 20.10.17Gitlab gitlab-ce:14.0.5-ce.0Jenkins相关依赖环境安装Java环境安装虽然我们是采用docker的方式安装Jenkins,所有的依赖镜像都已经打包好了。但是我们在后续...

李博帅1阅读 1.2k评论 1

封面图
不背锅运维:云原生下的CICD-3件套快速搭建合集:jenkins+harbor+gitlab
使用docker容器启动jenkins {代码...} 需要注意:/data 是宿主机的数据目录,请选用容量足够、性能好的文件系统必须显示声明-u root,使用root启动容器,否则容器不能正常启动宿主机的/var/run/docker.sock请确保...

不背锅运维阅读 660

封面图
快速创建Jenkins Job
1.Freestyle project 这个是jenkins的基础功能,可以用它来执行各种构建任务,他只能构建在一个电脑上,如果没有太多的需求,这个job基本够用了,它包含了所有基础功能.

用户bPtuda阅读 629

封面图
Jenkins
[链接]前置环境准备服务器 OS Linux CentOS数据库服务器 MYSQL ServerGithub账号Idea IDE一、简介开源平台常用于自动化测试、持续集成二、Jenkins基础下载Jenkins docker pull jenkins/jenkins第一次启动docker c...

阿南阅读 627

Jenkins 添加 Slave Agent 节点时报类文件不匹配错误
可以知道 Slave Agent 上的 JDK1.8 环境版本与 Jenkins Master Server 端的版本不匹配,我部署的 Jenkins Server 是 2.361.2,因此需要 Slave Agent 上提供的应该是 JDK11 或者更新的版本。

觅食的蛇阅读 446

jenkins+docker进行微服务部署
由于公司使用的是内部网络,没有打开互联网,所以在进行jenkins构建的时候,没法下载对应插件,刚开始使用镜像的方式制作了jenkins镜像,但是jenkins镜像内部又缺少maven等插件,弄了许久还是需要下载插件;感觉...

startshineye阅读 400

4 声望
1 粉丝
宣传栏