2

Our Craft site needs to exchange data with our customer in-house APP. And at some point it needs for the APP to POST us updates. We set some sort of API with a Api and Secret Key to exchange between platform. Everything works fine on DEV as we turned off the enableCsrfProtection. But sure enough won't work and obviously we need to keep it on for all the rest of the pages for security reason.

So my question is : How can the APP post us data with this security ON ? I mean it's not like we put a form with the value or anything like this. I'm puzzled. Sure enough I research and saw this page: https://craftcms.com/knowledge-base/enabling-csrf-protection#updating-your-javascript but I don't see the solution it this... Maybe it's just me ! :D

Thanks for your input.

1
  • Another way of asking this (if I understand correctly) might be "How can I POST to a CSRF-protected action without a session?" Apr 4 at 20:45

1 Answer 1

2

There are a few answers about controlling CSRF protection on a per-endpoint basis, or for requests where a token needs to be created on-the-fly, but I think your question is unique.

It sounds like your client's internal application will be issuing a “stateless” request (i.e. without a session), sort of like a webhook. I'd also be willing to be that they can't or won't provide support for a custom handler capable of emulating a session—something that would require at least two discrete requests; one to start the session and get a token, and a second to submit it and the payload.

If you have a custom Controller receiving the data, you can tell it to ignore CSRF, without disabling it for the entire app…

class AppHookController extends Controller
{
    public $enableCsrfValidation = false;

    // ...

    public function actionReceiveData()
    {
        // Your processing logic!
    }
}

…or even for a single action…

class AppHookController extends Controller
{
    // ...

    public function beforeAction($action): bool
    {
        // Disable protection for only one action:
        if ($action->id === 'receive-data') {
            $this->enableCsrfProtection = false;
        }

        return parent::beforeAction($action);
    }

    public function actionReceiveData()
    {
        // Your processing logic!
    }
}

💡 Either of these could be combined with a kind of "shared secret" between your site and the internal application that can be checked during the request.

If you are piggybacking on a built-in Craft controller, you can be notified when it is about to process a request:

Event::on(
    EntriesController::class,
    EntriesController::EVENT_BEFORE_ACTION,
    function (ActionEvent $e) {
        $action = $e->action;
        $controller = $action->controller;

        if ($e->action->id === 'receive-data') {
            $controller->enableCsrfProtection = false;
        }
    });

☠️ I would strongly advise not deploying this solution, as misconfiguration can significantly impact the security of your application!

1
  • Thanks for your answer. That's exactly it ! Apr 12 at 15:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.