标签:
假如跨站伪造请求成功,怎么保证 ajax 的数据安全性?
答主 bumfod 说的确实有道理。crsf
的成因在一定程度上确实是由于http有状态的原因
(cookie维持状态),并不是我之前所说的是 http无状态的原因
。
在此如果有人被误导,我表示抱歉。
我们如果能验证请求确实来是用户确认(自愿)发出的,而不是用户误导的情况下发出的,就能解决这个问题。
检查Referer标头确实是一种方案,但是该标头也有可能被篡改,而且浏览器的实现不一。
以RESTful服务为例。
我们假设有一个资源Books
我们现在要对 Books
资源进行 POST
动作(请求)。那如何保证该动作不会被 csrf
。
通常的做法是
我们在请求 POST 之前,要获取到改对POST
请求的 token
。只要在 POST
请求时携带对应的 token 才可以 200, 否则 就是 403。 (token 的生成算法多种多样,主要看需求)
// 获取 token
token = get_token(resource:‘Books‘)
// 请求
request(book).token(token).post()
传统 form 表单提交,为了解决 csrf
都会提供如下解决方案。
<form action="/books" method="POST" >
<input type="text" name="name" />
<input type="text" name="author" />
<input type="text" name="publisher" />
<!-- csrf token -->
<input type="hidden" name="token" value="j8i32hh2n2e8jdij92ecndaj9923dna9" />
</form>
在打开表单页面的时候,会给表单生成一个令牌(token),当表单提交的时候,就会根据令牌来验证表单的合法性。
token 的算法多种多样,有依赖于session的,有依赖于请求指纹的,有依赖于ip的,还有依赖于cookie的 等等。具体看业务需求。大多数 web 框架的实现都是使用httpOnly cookie
,但是
RESTful服务框架都是依赖于请求指纹的。这些没有什么好坏之分。
请求指纹
: 一个请求有很多指纹信息,比如说请求的url和url中的信息,(‘/books‘),请求的ip,请求的UA,请求的标头信息,等等。请求指纹来计算token的话,可以保证无状态特性。
依赖ip
: 对请求的客户端 ip 值进行 hash 来作为 token;这样是没有状态的。
依赖session
: 这种方法很适用于web网站,就是当用户登录后,对用户的请求根据用户的信息生成 token 存放到 session 中。
例如:
我们要修改系统至用户的信息。
/users
资源
在 post 之前我们需要先获取 修改资源的 token。
请求 获取 token
GET /access_token?uid=1001&scope=users&authorize=sujijd1026ajkshd28saos29hdandja HTTP/1.1
Authorization: sujijd1026ajkshd28saos29hdandja
Accept: application/json;charset=utf8
Cache-Control: no-cache
Host: localhost:8080
后端可以根据标头中的 Authorization
, url 查询字符串中的 uid, scope, authorize。来生成 access_token
比如使用 AES 堆成加密的base64字符串。最后能够再加点盐。
(这里标头和查询字符串中都存在 Authorization
,可以自己取舍。)
返回 token
HTTP/1.1 200 OK
Connection → keep-alive
Content-Length → 2612
Content-Type → application/json; charset=utf-8
{"access_token": "diaj2iejqd8qqld9k92doijq9j2oie1u"}
修改user的post请求
POST /users?access_token=diaj2iejqd8qqld9k92doijq9j2oie1u HTTP/1.1
Authorization: sujijd1026ajkshd28saos29hdandja
X-Token: diaj2iejqd8qqld9k92doijq9j2oie1u
Accept: application/json;charset=utf8
Cache-Control: no-cache
Host: localhost:8080
{"name": "如何变得有思想", "author": "阮一峰", "publisher": "人民邮电出版社"}
以上演示了如何组织一个使用令牌来实现csrf的请求。
回到问题的开始 ajax 该怎么做?
依然使用 /user/1001
为例,我们使用指纹加密的方法生成token。
/access_token
为令牌资源
var $request = function(ajax_param1) {
return function(data){
return $.ajax(merge(ajax_param1, {‘data‘: data}));
};
};
var get_token = $request({
‘type‘: ‘GET‘,
‘url‘: ‘/access_token‘
});
var create_book = function(book){
// post
return get_token({uid: 1001}).then(function(token){
return $request({
‘type‘: ‘POST‘,
‘url‘: ‘/books‘,
// 关键点
‘headers‘: {
‘x-crsf-token‘: token.access_token,
‘Authorization‘: ‘sujijd1026ajkshd28saos29hdandja‘
}
})(book);
});
}
var book = {name: ‘如何变得有思想‘, author: ‘阮一峰‘, publisher: ‘人民邮电出版社‘};
create_book(book).then(function(res){
console.log(res);
// 200 ok! book created
});
将token放到url上还是放到标头中,具体看开发者的喜好了。
标签:
原文地址:http://www.cnblogs.com/faming/p/4845485.html