Reputation:
Currently I am working on 2 websites. One website(Website A) is a simple CMS and the other website(Website B) is a regular website for the user where they can manage their profiles etc. The user can browse packages in the CMS. These packages are received using an AJAX request from the other site (Website B). these packages can also be bought. When the user buys a package(Website A), a post request is being send to the other website(Website B).
So to clarify, Say, for instance we have websites A and B. When the user on website A buys a package, a post request is being send to "B.com/package/purchase". There is only one problem with this design. In Laravel a csrf token has to be send with every form. Because I do a POST request to another website, I cannot generate a CSRF token from website A, because then the request will always be expired. So I have to use the CSRF token from website B. I have tried that but the request still returns a 419 Page Expired error. How can I solve this?
The form on Website A: (This form is inside an javascript append, thus the quotes.
'<form method="POST" action="https://rainierlaansite.test/package/' + el.token +'/purchase" id="purchase-form">' +
'<input type="hidden" value="'+ el.token +'" name="package_token">' +
'<input name="_token" type="hidden" id="csrf-token" value=' + data[1] + '>' +
'<h4>' +
'<a href="#" id="download_package" class="badge badge-pill '+ (el.price == 0 ? 'badge-primary': 'badge-light') +'" onclick="document.getElementById(\'purchase-form\').submit();">' +
(el.price == 0 ? 'Download': '$ ' + el.price) +
'</a>' +
'</h4>' +
'<form>' +
The AJAX request on website A:
<script>
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), 'X-Requested-With': 'XMLHttpRequest'},
url: 'https://www.rainierlaansite.test/api/packages/get',
type: 'GET',
data: {},
success: function(data) {
$('#package-loading').fadeOut();
let wrapper = $("#packages-wrapper");
let popup_list = $('.popup-list');
let popup = 'popup-id';
if(data == null) {
console.log('lol')
}
$.each(data[0], function(index, value) {
let el = data[0][index];
wrapper.append(
'<div class="row my-4" data-id='+ el.id +'>' +
'<div class="col-2 d-flex justify-content-center"><i class="fad fa-archive fa-2x"></i></div>' +
'<div class="col-6">' +
'<a href="#" class="popup" data-popup-id="'+ el.id +'"><h6 class="m-0">'+ el.name +'</h6></a>' +
'<p class="m-0 sub-text">'+ el.description +'</p>' +
'</div>' +
'<div class="col-4 d-flex justify-content-end align-items-center">' +
'<a href="#" id="download_package" class="badge badge-pill badge-light popup '+ (el.price == 0 ? 'badge-primary': 'badge-light') +'" style="font-size: 14px;" data-popup-id="'+ el.id +'">' + (el.price == 0 ? 'Download': '$ ' + el.price) +'</a>' +
'</div>' +
'</div>' + '<hr>'
);
popup_list.append(
'<div class="package-popup shadow popup-'+ el.id +'">' +
'<div class="package-popup-dialog animated zoomIn show faster">' +
'<div class="package-popup-content">' +
'<div class="row">' +
'<div class="col-2">' +
'<div class="row">' +
'<div class="col-12 d-flex justify-content-center">' +
'<i class="fad fa-archive fa-3x"></i>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="col-7">' +
'<div class="row">' +
'<div class="col-12">' +
'<h4 class="m-0">' + el.name + '</h4>' +
'<p class="sub-text">' + el.creator + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="col-3 text-center">' +
'<form method="POST" action="https://rainierlaansite.test/package/' + el.token +'/purchase" id="purchase-form">' +
'<input type="hidden" value="'+ el.token +'" name="package_token">' +
'<input name="_token" type="hidden" id="csrf-token" value=' + data[1] + '>' +
'<h4>' +
'<a href="#" id="download_package" class="badge badge-pill '+ (el.price == 0 ? 'badge-primary': 'badge-light') +'" onclick="document.getElementById(\'purchase-form\').submit();">' +
(el.price == 0 ? 'Download': '$ ' + el.price) +
'</a>' +
'</h4>' +
'<form>' +
'</div>' +
'<div class="offset-2 col-7">' +
'<div class="rating">' +
'<span><i class="fas fa-star yellow"></i></span>' +
'<span><i class="fas fa-star yellow"></i></span>' +
'<span><i class="fas fa-star yellow"></i></span>' +
'<span><i class="fas fa-star yellow"></i></span>' +
'<span><i class="fas fa-star grey"></i></span>' +
'<small><a href="">· Uit 300 beoordelingen</a></small>' +
'</div>' +
'<small>Nog geen beoordelingen</small>' +
'</div>' +
'<div class="col-3 text-center">'+
'<i class="far fa-download"></i> ' + el.downloads +
'</div>' +
'</div>' +
'<div class="row my-5">' +
'<div class="col-12">' +
'<nav>' +
'<div class="nav nav-tabs" id="nav-tab" role="tablist">' +
'<a class="nav-item nav-link active" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="true">Details</a>' +
'<a class="nav-item nav-link" id="nav-profile-tab" data-toggle="tab" href="#nav-profile" role="tab" aria-controls="nav-profile" aria-selected="false">Reviews</a>' +
'<a class="nav-item nav-link" id="nav-contact-tab" data-toggle="tab" href="#nav-contact" role="tab" aria-controls="nav-contact" aria-selected="false">Version history</a>' +
'</div>' +
'</nav>' +
'<div class="tab-content" id="nav-tabContent">' +
'<div class="tab-pane fade show active py-4" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">' +
'<p>' + el.description + '</p>' +
'</div>' +
'<div class="tab-pane fade py-4" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">' +
'Dit is twee tekst' +
'</div>' +
'<div class="tab-pane fade py-4" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab">' +
'Dit is tekst 3' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
});
$('.popup').on('click', function () {
if($(this).data(popup)) {
let item = $('.popup-' + $(this).data(popup));
item.addClass('show');
$(item).on('click', function(event) {
if (event.target.classList.contains("shadow")) {
item.removeClass('show');
}
})
}
});
},
error: function(e) {
$('#package-error').fadeIn().text("Unfortunately there was an error retrieving the packages");
}
});
</script>
What the AJAX request receives
public function get()
{
$csrf = json_encode(csrf_token());
return response()
->json([Package::all(), $csrf]);
}
Upvotes: 1
Views: 1416
Reputation: 2932
Laravel makes it easy to protect your application from cross-site request forgery (CSRF) attacks. Cross-site request forgeries are a type of malicious exploit whereby unauthorized commands are performed on behalf of an authenticated user.
Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the one actually making the requests to the application.
By default, laravel prevents cross-site requests by using the CSRF token. If you want you can avoid CSRF verification by adding the URI to except array in VerifyCsrfToken Middleware.
Set the VerifyCsrfToken Middleware in your App\Http\Middleware of the https://www.rainierlaansite.test application as follows
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'api/packages/get',
];
}
Upvotes: 1