【发布时间】:2012-02-23 18:49:04
【问题描述】:
所以我有一个基本的 .ajax() POST 方法到 PHP 文件。
我需要什么安全措施?
周围的一些帖子提到使用您通过 AJAX 发送并在 PHP 文件中验证的隐藏 MD5 输入字段。这是一个足够好的方法吗?
【问题讨论】:
标签: jquery ajax security post csrf
所以我有一个基本的 .ajax() POST 方法到 PHP 文件。
我需要什么安全措施?
周围的一些帖子提到使用您通过 AJAX 发送并在 PHP 文件中验证的隐藏 MD5 输入字段。这是一个足够好的方法吗?
【问题讨论】:
标签: jquery ajax security post csrf
来自 CSRF 的风险是外部站点可能会向您的站点发送数据,并且用户浏览器会自动发送身份验证 cookie。
您需要某种方式让接收操作(您的 $.ajax() 方法正在向其发送 POST 数据)能够检查请求是否来自您网站上的另一个页面,而不是来自外部网站。
有几种方法可以做到这一点,但推荐的方法是在请求中添加一个令牌,您可以检查它并且黑客无法访问。
最简单的:
$.ajax() 请求添加一个参数。黑客无法访问您的数据库,也无法真正读取您发送给用户的页面(除非他们受到 XSS 攻击,但这是另一个问题),因此无法欺骗令牌。
对于令牌而言,重要的是您可以预测(并验证)它而黑客不能。
因此,最容易生成长而随机的内容并将其存储在数据库中,但您可以构建一些加密的内容。不过,我不会只对用户名进行 MD5 - 如果 CSRF 攻击者弄清楚如何生成您的令牌,您将被黑客入侵。
另一种方法是将令牌存储在 cookie(而不是您的数据库)中,因为攻击者无法读取或更改您的 cookie,只会导致它们被重新发送。那么你就是 HTTP POST 数据中的令牌匹配 cookie 中的令牌。
您可以使这些更复杂,例如每次成功使用时都会更改的令牌(防止重新提交)或特定于用户和操作的令牌,但这是基本模式。
【讨论】:
就请求伪造而言,客户端如何发送请求并不重要,重要的是它如何接收。与任何其他类型的帖子相同的 CSRF 规则适用于 ajax 帖子。
我建议阅读CSRF prevention cheat sheet。使用每个用户的秘密令牌是最常见的保护形式。
【讨论】:
严格来说,不需要令牌,但您仍应保护任何更改状态的函数免受 CSRF 影响。
CRSF 绝对是一种风险,即使请求是通过 AJAX 发出的。这是因为 AJAX 请求可以跨域传递——同源策略只防止读取,而不是写入。而且传统表单可能能够发送与您的 AJAX 完全相同的 POST 请求,而您当前的服务器端代码可能无法检测到这一点。
让您的服务器端代码检测请求是否来自您自己的站点的一种简单方法是添加与 AJAX 请求一起发送的标头。重要的是您的服务器端代码检查此标头的存在。不一定需要随机令牌。
之所以有效,是因为:
为了防御网络上的任何未来发展,同时实现一个随机令牌可能是个好主意。这需要以某种方式与当前用户会话相关联。如果没有实现令牌,它目前是不可利用的,但在网络漫长而曲折的历史中,缺乏令牌可能会被 Flash 和其他浏览器插件利用。在一个完美的世界中,HTML5 和生活标准应该意味着像这样的插件已经成为过去,但是,谁知道即将发生什么,所以为了增加深度防御和未来的证明,令牌也是推荐。
【讨论】:
这是一个可以用 django 尝试的简单演示:
在 HTML 页面上
{%block content%}
<form id="userForm">
{%csrf_token%}
<input type="text" id="username" placeholder="User Name">
<input type="password" id="password" placeholder="Password">
</form>
{%endblock%}
Java 脚本代码
%(document).on('submit','#userForm',function(e){
e.preventDefault();
$.ajax({
type = 'POST',
url:'path/to/url',
data:{
username:$('#username').val(),
password:$('#password').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken').val()
},
success:function(data){
alert('Successfull');
}
});
});
【讨论】: