Json secure with csrf token

Hi,
I’am struggeling with securing my json file from direct access.

how do I have to implement the get(‘csrf’) method, in the json file?

const csrf = "<?= csrf() ?>";

      fetch("/api/pages/example", {
          method: "GET",
          headers: {
            "X-CSRF" : csrf
          }
        })

Thanks

This looks like the example here: Authentication | Kirby CMS

But I’m missing the context where you are using this code?

Hi @texnixe,
in my template I catch the Data width:

const csrf = "<?= csrf() ?>";

      fetch("/fotografen.json" {
          method: "GET",
          headers: {
            "X-CSRF" : csrf
          }
        })

and my json is:

<?php


$json = [];

foreach($data as $mapentry) {	
	
	$json[] = [
    'title'      		=> (string)$mapentry->title(),
    'city'       		=> (string)$mapentry->city(),
    'street'     		=> (string)$mapentry->street(),
    'latitude'   		=> (string)$mapentry->latitude(),
    'longitude'  		=> (string)$mapentry->longitude(),
    'category'   		=> (string)$category,
    'box-border-color'   => (string)$color,
    'link'       			=> (string)$mapentry->link(),
    'iconlink'   		=> (string)$mapentry->category(),
    'imageurl'	 	=> (string)$mapentry->imagelink(),
    'logourl'	   		=> (string)$mapentry->logolink()
  ];

}

echo json_encode($json, JSON_UNESCAPED_UNICODE);

but where and how do I have to check the token?

Thanks

My Solution now is:

    [
    'pattern' => '(:any).json',
    'action'  => function () {
    $customHeader = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? null;
    		
     // Secure JSON output from direct access in production environment
    if ($customHeader !== 'fetch' && $customHeader !== 'XMLHttpRequest') {
        go(url('error'));
    }
    		
  $this->next();
  }
 ]

my template:

      fetch("/fotografen.json", {
          method: 'GET',
          headers: {
              'X-Requested-With': 'fetch'
           }
        })

This works now.
I have two pages one works with fetch, but this page rely on webgl, the other page of the site supports older browsers too with jquery and XMLHttpRequest:

var xhr = new XMLHttpRequest();
$.getJSON('/lighttable.json')

But if I woud use csrf token, where should I check the token?

Thanks

If your json is really saved somewhere accessible to the public, apache will serve that file directly without going through PHP and Kirby.

Only if you’re keeping your json secret and serve it only via an API endpoint, you can block the requests.

In PHP you can use the csrf() helper function both to generate and to check a token.
See https://getkirby.com/docs/reference/templates/helpers/csrf

If you’re sending the token via a header, like you do in the opening post of this thread, you can get that token via $kirby->request()->csrf(). Therefore you should be able to check if the submitted token is valid with something like this:

$submittedToken = kirby()->request()->csrf();
if(csrf($submittedToken)) {
 //tokens match load and return your json
} else {
  //show error
}

PS: csrf tokens only prevent some kind of xss attacks, their purpose is not to prevent people from stealing your data and use it on other sites. Other sites (on the server side) could just request a token from yours and then request the json file with that. Adding a csrf check doesn’t really add anything more to keep your data secret than the default “same origin policy” in browsers does.

Thank you @rasteiner for your reply,
does the header check with fetch or XMLHttpRequest secure anything or could I build a page somewhere else end fetch the data, if one know the json url?
Taki

anyone could write, for example, a php script that requests stuff from your server without you noticing any difference. When doing their request they just have to send the X-Requested-With: fetch header with it and there’s nothing reasonable you can do about that.

You have no guarantee that the headers you receive are “real”. Just like you can’t prevent people from just manually saving the json file to their hard disk by opening a developer console.

if it’s sensible data it should go behind a login, or some other kind of auth method;
if you just don’t want other websites to lazily fetch your json directly in a users browser, you don’t need to do anything because browsers won’t allow that (unless you explicitly allow that kind of resource sharing - I doubt you do).

Edit:
of course, adding something like the csrf check or the header check, while not being a “proper security” measure, could just be enough hassle for people to discourage them from trying further. It really depends on the importance of the data, I guess

1 Like

Thank you @rasteiner for your explanation. I’am going with your “Edit”.