Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Setting up Iframe protection (#1178)
Browse files Browse the repository at this point in the history
  • Loading branch information
enmaboya authored Sep 3, 2022
1 parent e449664 commit 7ac7829
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/Http/Middleware/IframeProtection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Osiset\ShopifyApp\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Osiset\ShopifyApp\Contracts\Queries\Shop as IShopQuery;
use Osiset\ShopifyApp\Objects\Values\ShopDomain;

/**
* Responsibility for protection against clickjaking
*/
class IframeProtection
{
/**
* The shop querier.
*
* @var IShopQuery
*/
protected $shopQuery;

/**
* Constructor.
*
* @param IShopQuery $shopQuery The shop querier.
*
* @return void
*/
public function __construct(
IShopQuery $shopQuery
) {
$this->shopQuery = $shopQuery;
}

/**
* Set frame-ancestors header
*
* @param Request $request The request object.
* @param \Closure $next The next action.
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);

$shop = Cache::remember(
'frame-ancestors_'.$request->get('shop'),
now()->addMinutes(20),
function () use ($request) {
return $this->shopQuery->getByDomain(ShopDomain::fromRequest($request));
}
);

$domain = $shop
? $shop->name
: '*.myshopify.com';

$response->headers->set(
'Content-Security-Policy',
"frame-ancestors https://$domain https://admin.shopify.com"
);

return $response;
}
}
3 changes: 3 additions & 0 deletions src/ShopifyAppProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use Osiset\ShopifyApp\Http\Middleware\AuthProxy;
use Osiset\ShopifyApp\Http\Middleware\AuthWebhook;
use Osiset\ShopifyApp\Http\Middleware\Billable;
use Osiset\ShopifyApp\Http\Middleware\IframeProtection;
use Osiset\ShopifyApp\Http\Middleware\VerifyShopify;
use Osiset\ShopifyApp\Macros\TokenRedirect;
use Osiset\ShopifyApp\Macros\TokenRoute;
Expand Down Expand Up @@ -305,6 +306,8 @@ private function bootMiddlewares(): void
$this->app['router']->aliasMiddleware('auth.webhook', AuthWebhook::class);
$this->app['router']->aliasMiddleware('billable', Billable::class);
$this->app['router']->aliasMiddleware('verify.shopify', VerifyShopify::class);

$this->app['router']->pushMiddlewareToGroup('web', IframeProtection::class);
}

/**
Expand Down
66 changes: 66 additions & 0 deletions tests/Http/Middleware/IframeProtectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace Osiset\ShopifyApp\Test\Http\Middleware;

use Illuminate\Auth\AuthManager;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Osiset\ShopifyApp\Http\Middleware\IframeProtection;
use Osiset\ShopifyApp\Storage\Queries\Shop as ShopQuery;
use Osiset\ShopifyApp\Test\TestCase;

class IframeProtectionTest extends TestCase
{
/**
* @var AuthManager
*/
protected $auth;

public function setUp(): void
{
parent::setUp();

$this->auth = $this->app->make(AuthManager::class);
}

public function testIframeProtectionWithAuthorizedShop(): void
{
$shop = factory($this->model)->create();
$this->auth->login($shop);

$domain = auth()->user()->name;
$expectedHeader = "frame-ancestors https://$domain https://admin.shopify.com";

$request = new Request();
$shopQueryStub = $this->createStub(ShopQuery::class);
$shopQueryStub->method('getByDomain')->willReturn($shop);
$next = function () {
return new Response('Test Response');
};

$middleware = new IframeProtection($shopQueryStub);
$response = $middleware->handle($request, $next);
$currentHeader = $response->headers->get('content-security-policy');

$this->assertNotEmpty($currentHeader);
$this->assertEquals($expectedHeader, $currentHeader);
}

public function testIframeProtectionWithUnauthorizedShop(): void
{
$expectedHeader = 'frame-ancestors https://*.myshopify.com https://admin.shopify.com';

$request = new Request();
$shopQuery = new ShopQuery();
$next = function () {
return new Response('Test Response');
};

$middleware = new IframeProtection($shopQuery);
$response = $middleware->handle($request, $next);
$currentHeader = $response->headers->get('content-security-policy');

$this->assertNotEmpty($currentHeader);
$this->assertEquals($expectedHeader, $currentHeader);
}
}

0 comments on commit 7ac7829

Please sign in to comment.