如何使用 CSRF 令牌进行跨域 Ajax 调用?
Posted
技术标签:
【中文标题】如何使用 CSRF 令牌进行跨域 Ajax 调用?【英文标题】:How to make cross-domain Ajax calls with CSRF token? 【发布时间】:2013-11-15 06:22:03 【问题描述】:我的 Django 应用模板中有一个典型的登录表单(直接使用 Bootstrap,而不是通过某些插件):
<form class="form-signin" method="post" action="/site_manager/login/" id="form-signin"> % csrf_token %
<h2 class="form-signin-heading">Please sign in</h2>
<div class="control-group">
<label class="control-label" for="login">Login:</label>
<div class="controls">
<input size="50" name="username" id="username" required="true" type="text" class="form-control" placeholder="Login" intermediateChanges=false>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password:</label>
<div class="controls">
<input size="50" name="password" id="password" required="true" type="password" class="form-control" placeholder="Password" intermediateChanges=false>
</div>
</div>
<button name="submit" id="submit" value="Log in" type="submit" class="btn btn-primary pull-right">Sign in</button>
</form>
这是通过requests module执行远程身份验证的相应视图:
def login_view(request):
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
headers = 'content-type': 'application/json', 'username':username, 'password':password
r = requests.get(remote_server_url, auth=(username, password), headers=headers)
if r.status_code == 200:
user = authenticate(username=username, password=password)
if user == None:
user = User.objects.create_user(username.encode('ascii', 'ignore'), "", password)
user = authenticate(username=username, password=password)
login(request, user)
request.session.set_expiry(0)
return HttpResponseRedirect('<index_page>')
else:
# redirects back to login page with some error message
一旦登录成功,我可以使用 javascript 查询 CSRF 令牌,正如 here 所解释的那样,我的计划是出于其他目的(例如 RESTful 查询)对远程服务器进行 Ajax 调用(通过 SSL)。正如上面的代码所示,该服务器使用基本身份验证。所以我想在每次Ajax调用的header中设置CSRF token,但这不符合同源原则:
var csrftoken = $.cookie('csrftoken'); // using the jQuery Cookie plugin
$.ajaxSetup(
headers:
'Authorization': "Basic XXXXX"
beforeSend: function(xhr, settings)
xhr.setRequestHeader("X-CSRFToken", csrftoken);
);
$.ajax(
type: "GET",
dataType: "jsonp",
url: remote_server_url+'/api/v1/someRESTfulResource/',
contentType: 'application/json',
success: function(data)
// some operations with data
);
Ajax 调用中使用的remote_server_url
和身份验证是一样的,不与Django 应用共享同一个域。据我所知,这是一个安全风险。出于同样的原因,我也不想在 Javascript 代码中提供纯文本密码。如何使用用户凭据安全地对远程服务器进行 Ajax 调用?
【问题讨论】:
有些相关:***.com/questions/17931158/… 你能显示你试图尝试的 ajax 调用吗?它应该是直截了当的。 更新了问题 :) @AndrewSledge:我的案例更加基础,除了 Django 和 jQuery 之外,什么都没有。我无法从那里的答案中真正挽救任何对我有帮助的东西。 【参考方案1】:我正在为我想用 django 进行 Ajax POSTS 的页面进行 Javascript 初始化:
$(document).ajaxSend(function(event, xhr, settings)
function sameOrigin(url)
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isnt scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
function safeMethod(method)
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
if (!safeMethod(settings.type) && sameOrigin(settings.url))
xhr.setRequestHeader("X-CSRFToken", ' csrf_token ');
);
我不记得我在哪里找到它了,但是在使用它之后,我可以做这样的 Ajax 帖子:
$.post("% url 'foo' %", "data="+myjson, function(data)
if(data['result']=="ok")
window.location.replace('% url "bar" %');
else
alert("Data Err!");
).error(function()
alert("Ajax error!");
);
【讨论】:
它看起来也遵循同源原则。如果我的 Django 应用程序在我的本地主机上运行,并且我正在对https://www.suchandsuch.com/someservice
进行 Ajax 调用,那么它会工作吗?
我的代码将 CSRFToken 添加到您的 post 请求中,以便您可以使用 django 进行 POST。但是,您必须了解,由于同源策略,您不能对不同的域执行 POST 请求!如果您愿意,您只能使用 JSONP 进行 GET 请求。但是你根本不需要我的代码,因为 GET 不需要 CSRFToken!以上是关于如何使用 CSRF 令牌进行跨域 Ajax 调用?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Cakephp 3 的 ajax 调用中定义 CSRF 令牌。此外,对于某些 ajax 请求,如何关闭 CSRF
用于 AJAX CORS 的 Laravel CSRF 令牌
如何使用 ajax 在 LARAVEL 中获取新的 CSRF 令牌
如何在 AJAX 中传递 Django csrf 令牌(没有 jQuery)