ajax 如何保证数据的安全性?

bachelor
  • 963

假如跨站伪造请求成功,怎么保证 ajax 的数据安全性?

回复
阅读 14k
4 个回答
✓ 已被采纳

从本质来讲ajax请求就是http请求。

问题的根源

答主 bumfod 说的确实有道理。crsf 的成因在一定程度上确实是由于http有状态的原因(cookie维持状态),并不是我之前所说的是 http无状态的原因
在此如果有人被误导,我表示抱歉。

我们如果能验证请求确实来是用户确认(自愿)发出的,而不是用户误导的情况下发出的,就能解决这个问题。

检查Referer标头确实是一种方案,但是该标头也有可能被篡改,而且浏览器的实现不一。

举个例子

以RESTful服务为例。

我们假设有一个资源Books

我们现在要对 Books 资源进行 POST 动作(请求)。那如何保证该动作不会被 csrf

通常的做法是

我们在请求 POST 之前,要获取到改对POST请求的 token。只要在 POST 请求时携带对应的 token 才可以 200, 否则 就是 403。 (token 的生成算法多种多样,主要看需求)

http请求实例

 // 获取 token
 token = get_token(resource:'Books')

 // 请求
 request(book).token(token).post()

表单实例

传统 form 表单提交,为了解决 csrf 都会提供如下解决方案。

html <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 怎么来的

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

httpGET /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 为令牌资源

javascript 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上还是放到标头中,具体看开发者的喜好了。

身份校驗是一切安全/加密傳輸的前提。

保障傳輸數據安全,首先要防止身份僞造。

防止身份僞造,只要設置一段只有身份正確時纔可能有的信息即可。

這種東西叫做密碼(password,用於身份校驗的保密字符串,不一定非得是用戶名/密碼組合中的密碼,也可以是 token)。

題主關注的是跨站請求僞造,那麼只要把密碼儲存在 CSRF 所無法得到的地方即可。

CSRF 只能僞造用戶進行操作,無法僞造用戶獲取信息。

然而 cookies 會被瀏覽器自動一起發送,達不到識別的目的,

所以一般的做法是在表單中添加一項 token:

由於 CSRF 的本質在於攻擊者欺騙用戶去訪問自己設置的地址,所以如果要求在訪問敏感數據請求時,要求用戶瀏覽器提供不保存在 cookie 中,並且攻擊者無法偽造的數據作為校驗,那麼攻擊者就無法再執行 CSRF 攻擊。這種數據通常是表單中的一個數據項。服務器將其生成並附加在表單中,其內容是一個偽亂數。當客戶端通過表單提交請求時,這個偽亂數也一並提交上去以供校驗。正常的訪問時,客戶端瀏覽器能夠正確得到並傳回這個偽亂數,而通過 CSRF 傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽亂數的值,服務器端就會因為校驗 token 的值為空或者錯誤,拒絕這個可疑請求。

http://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0


樓下認爲 CSRF 的本質是 HTTP 請求無狀態,

這是錯誤的(現已修正,點讚!)。

CSRF 恰恰就是利用了瀏覽器存在漏洞的對「有狀態」HTTP 的實現,也就是 cookie。

所以,即便 HTTP 請求有狀態,只要瀏覽器不校驗調用者身份,依舊會被 CSRF。

CSRF 是欺騙用戶瀏覽器,讓其以用戶的名義執行操作。

(同樣出自維基百科)

你知道吗?

宣传栏