CSRF(Cross-site request forgery)跨站请求伪造,通过伪装成受信任用户的请求来利用受信任的网站。
攻击通过在授权用户访问的页面中包含链接或者脚本的方式工作。例如:用户Bob可能正在浏览聊天论坛(网站B),而同时攻击者Alice也论坛中,并且刚刚发布了一个含有Bob银行链接(网站A)的图片消息。假如这个图片包含的链接是一次取款操作,而Bob恰好打开了银行网站,或者浏览器自动保存了包含授权信息的cookie。那么当Bob的浏览器尝试加载图片时将提交这个取款链接和他的cookie,于是在未经Bob允许下便授权了这次操作。
这利用了web中用户身份验证的一个漏洞:简单的身份验证仅仅能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
CSRF的防御思路在于,对web站点,将持久化的授权方法(例如cookie或者HTTP授权)切换为瞬时的授权方法(比如在每个form中提供隐藏field)。
具体防御手段
(1) 提交验证码
在表单中添加一个随机的数字或字母验证码。通过强制用户和应用进行交互。来有效地遏制CSRF攻击
(2) Referer Check
检查HTTP请求头中的referer字段,查看请求来源是否正常(referer可被更改,不可靠)
(3) token验证
在 HTTP 请求中以參数的形式添加一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,假设请求中没有 token 或者 token 内容不对,则觉得可能是 CSRF 攻击而拒绝该请求。
token相较于cookie能够防御CSRF的原因在于,cookie存储于用户浏览器中且当当前会话结束后仍可能继续存在且有效,在访问网站时会被自动提交。而token是以会话(session)为单位,由服务器在用户成功登陆后分配,在请求时被加在参数中或者form表单中一起提交,无法被攻击者通过跨站请求的方式获取。
举个简单的例子:
假如银行页面没有设置csrftoken,攻击者可以通过下面这行代码诱导用户点击并完成取款操作(身份验证由cookie完成)
但加上csrftoken以后,取款操作的请求变成
http://www.mybank.com/Transfer.php?toBankId=11&money=1000&csrftoken='xxx'
攻击者无法知晓csrftoken的值,也就无法完成操作了
CrumbIssuer是一个为了抵御CSRF攻击而生成名为crumb值的算法。crumb通常是对能够唯一标识发送请求的代理(用户端)的信息 的hash值,并且其会被加密以防第三方伪造。
这个crumb值就相当于上面所讲的csrftoken值,由服务器端在用户登录时生成并发送给用户,之后用户每次登录时都需要对其进行验证。为了保证csrftoken不会被猜测或者伪造,生成方式是获取用户信息进行hash并加密。
在 Jenkins 中可以通过 系统管理->全局安全设置->CSRF Protection 启用或停用 CrumbIssuer ,在默认安全设置中是开启的。
hudson.security.csrf.CrumbIssuer
all() : 返回CrumbIssuer的所有描述符
getApi() : 返回所有公共方法
getDescriptor() : 获取crumb issuer的全局配置
initStaplerCrumbIssuer() : 设置Stapler
getCrumb([javax.servlet.ServletRequest request]) : 带参数就是基于请求中的特定用户信息生成crumb值,不带参数就是基于最近一次请求中的用户信息生成crumb值
getCrumbRequestField() : 获取crumb存储在哪个请求参数名中
issueCrumb(javax.servlet.ServletRequest request, String salt) : 创建一个crumb值,与getCrumb不同的是其还包含了一个用于生成hash的盐值(salt),安全性更高
validateCrumb() :有三种参数
1. javax.servlet.ServletRequest request - 指定请求, 盐值和请求参数都基于最近一次的配置
2. javax.servlet.ServletRequest request,MultipartFormDataParser parser - 指定表单数据和请求。盐值基于最近一次配置
3. javax.servlet.ServletRequest request,String salt,String crumb - 指定请求、盐值和crumb值