使用 ajax 提交表单时刷新 csrf 令牌是个好主意吗?
Is it a good idea to refresh csrf token when submitting form with ajax?
我想延长我的 CSRF 令牌有效期。我知道 laravel-caffeine 但如果页面闲置时间过长,令牌仍然会过期。(例如 24 小时以上)
所以我想出了一个想法,首先使用 ajax GET 方法检索最新的 csrf 令牌,然后使用这个刷新的令牌提交表单。
但我不确定是否存在一些安全问题。例如,假设可以在 http://example.com/get_csrf 获取最新的 csrf 令牌,并且对手也可以访问此 URL。不知道对手是否可以利用它并破坏csrf保护?
是的,您的担忧是正确的。该令牌用于防止其他网站通过受害者的会话创建对您网站的请求。通过 ajax 使令牌可请求可能会产生问题,如果可以从攻击网站完成的话。
您可以通过以下方式保护 /get_csrf
路线:
- 在提供表单时保存
csrf_token()
服务器端并将其保存在用户的一列中 table:
//in your controller
public function showMyForm(){
$user=auth()->user();
$user->last_csrf=csrf_token(); // save the csrf token
$user->save(); //persist to database
return view('myform');
}
- 让您的 get_csrf 路由验证旧令牌和 return 新令牌:
//in your other controller (Route::get('/get_csrf','Controller@getCSRF');)
public function getCSRF(Request $request){
$user=auth()->user();
$old_user_token=$user->last_csrf;
$old_client_token=$request->current_token;
if ($old_client_token && $old_user_token==$old_client_token){
// it's a match, update the token in the users table and send the new one
$user->last_csrf=csrf_token();
$user->save();
return csrf_token();
}
//no match, tell the client he is unauthorized to get the new csrf token
abort(401);
}
- ajax GET 使用页面当前的 csrf 作为有效载荷:(在这里使用 jquery 但你不需要)
$.ajax({
url:'/get_csrf',
method:'POST',
dataType:"json",
headers:{
// have the server treat the request as GET
'X-HTTP-Method-Override': 'GET'
},
data:{
// send the page's current csrf in the payload
current_token:document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
success(data){
// this is whatever the server sent back as the current csrf for this session
new_csrf=data;
// update the page's csrf
document.querySelector('meta[name="csrf-token"]').setAttribute('content',new_csrf);
//update any _token fields
document.querySelectorAll('input[name="_token"]').forEach(function(csrf_field){
csrf_field.setAttribute('value',new_csrf);
});
},
error(response){
// error handling. maybe console.log(response) here to see what happened?
}
});
- 像往常一样提交表单。
如果攻击是通过 iframe 进行的,js 代码可以截取受害者的 iframe 的屏幕截图,而不是解析 csrf 令牌,并且可以用于另一个请求(理论上)。
我想延长我的 CSRF 令牌有效期。我知道 laravel-caffeine 但如果页面闲置时间过长,令牌仍然会过期。(例如 24 小时以上)
所以我想出了一个想法,首先使用 ajax GET 方法检索最新的 csrf 令牌,然后使用这个刷新的令牌提交表单。
但我不确定是否存在一些安全问题。例如,假设可以在 http://example.com/get_csrf 获取最新的 csrf 令牌,并且对手也可以访问此 URL。不知道对手是否可以利用它并破坏csrf保护?
是的,您的担忧是正确的。该令牌用于防止其他网站通过受害者的会话创建对您网站的请求。通过 ajax 使令牌可请求可能会产生问题,如果可以从攻击网站完成的话。
您可以通过以下方式保护 /get_csrf
路线:
- 在提供表单时保存
csrf_token()
服务器端并将其保存在用户的一列中 table:
//in your controller
public function showMyForm(){
$user=auth()->user();
$user->last_csrf=csrf_token(); // save the csrf token
$user->save(); //persist to database
return view('myform');
}
- 让您的 get_csrf 路由验证旧令牌和 return 新令牌:
//in your other controller (Route::get('/get_csrf','Controller@getCSRF');)
public function getCSRF(Request $request){
$user=auth()->user();
$old_user_token=$user->last_csrf;
$old_client_token=$request->current_token;
if ($old_client_token && $old_user_token==$old_client_token){
// it's a match, update the token in the users table and send the new one
$user->last_csrf=csrf_token();
$user->save();
return csrf_token();
}
//no match, tell the client he is unauthorized to get the new csrf token
abort(401);
}
- ajax GET 使用页面当前的 csrf 作为有效载荷:(在这里使用 jquery 但你不需要)
$.ajax({
url:'/get_csrf',
method:'POST',
dataType:"json",
headers:{
// have the server treat the request as GET
'X-HTTP-Method-Override': 'GET'
},
data:{
// send the page's current csrf in the payload
current_token:document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
success(data){
// this is whatever the server sent back as the current csrf for this session
new_csrf=data;
// update the page's csrf
document.querySelector('meta[name="csrf-token"]').setAttribute('content',new_csrf);
//update any _token fields
document.querySelectorAll('input[name="_token"]').forEach(function(csrf_field){
csrf_field.setAttribute('value',new_csrf);
});
},
error(response){
// error handling. maybe console.log(response) here to see what happened?
}
});
- 像往常一样提交表单。
如果攻击是通过 iframe 进行的,js 代码可以截取受害者的 iframe 的屏幕截图,而不是解析 csrf 令牌,并且可以用于另一个请求(理论上)。